5

我有一个自定义适配器:

public class PhraseCustomAdapter extends BaseAdapter  
{  
public String original[];  
public String translation[];  
public String transcription[];  

public Activity context;  
public LayoutInflater inflater;  

public PhraseCustomAdapter(Activity context,String[] original, String[] translation, String[] transcription) {  
    super();  

    this.context = context;  
    this.original = original;  
    this.translation = translation;  
    this.transcription = transcription;  

    inflater = LayoutInflater.from(context);
    this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
}  

@Override  
public int getCount() {  
    // TODO Auto-generated method stub  
    return original.length;  
}  

@Override  
public Object getItem(int position) {  
    // TODO Auto-generated method stub  
     return position;
}  

public String getItemTranlation(int position) {  

    return translation[position];  
}  

public String getItemTranscription(int position) {  
    // TODO Auto-generated method stub  
    return transcription[position];  
}  

public String getItemOriginal(int position) {  
    // TODO Auto-generated method stub  
    return original[position];  
} 


@Override  
public long getItemId(int position) {  
    // TODO Auto-generated method stub  
    return position;  
}  

static class ViewHolder  
{  
    ImageView imgViewLogo;  
    TextView txtViewOriginal;  
    TextView txtViewTranslation;  
    TextView txtViewTranscription; 
}  

@Override  
public View getView(int position, View convertView, ViewGroup parent) {  

    ViewHolder holder;  
    if (convertView == null) {  
        holder = new ViewHolder();  
        convertView = inflater.inflate(R.layout.phrase_row, null);  

        holder.imgViewLogo = (ImageView) convertView.findViewById(R.id.imgViewLogo);  
        holder.txtViewOriginal = (TextView) convertView.findViewById(R.id.txtViewOriginal);  
        holder.txtViewTranslation = (TextView) convertView.findViewById(R.id.txtViewTranslation);  
        holder.txtViewTranscription = (TextView) convertView.findViewById(R.id.txtViewTranscription);   

        convertView.setTag(holder);  
    }  
    else  
        holder=(ViewHolder)convertView.getTag();  


    holder.txtViewOriginal.setText(original[position]);  
    holder.txtViewTranslation.setText(translation[position]);  
    holder.txtViewTranscription.setText(transcription[position]);

    return convertView;  
}   

}

而且我需要实现android4风格的多选(长按,然后点击选择项目)。所以:

    lview1 = (ListView) findViewById(R.id.listViewPhrase);  
    adapter = new PhraseCustomAdapter(this, original, translation, transcription);  
    lview1.setAdapter(adapter);  
    lview1.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
    lview1.setMultiChoiceModeListener(new MultiChoiceModeListener() {

        @Override
        public void onItemCheckedStateChanged(ActionMode mode, int position,
                                              long id, boolean checked) {
            View view;
            if (checked){
                Log.v ("checked?", "YES");
                Log.v ("Position", Integer.toString(position));

                view = lview1.getChildAt(position);
                view.setBackgroundColor(Color.LTGRAY);


                original_list.add (adapter.getItemOriginal(position));
                translation_list.add (adapter.getItemTranlation(position));
                transcription_list.add (adapter.getItemTranscription(position));

                countSelected += 1;
            }
            if (!checked){
                Log.v ("checked?", "NO");
                Log.v ("Position", Integer.toString(position));


                for (int i = 0; i < original_list.size(); i++)
                {
                    if (original_list.get(i) == adapter.getItemOriginal(position)){
                        original_list.remove (i);
                        translation_list.remove (i);
                        transcription_list.remove (i);  
                    }
                }
                countSelected -= 1;
            }


            mode.setTitle(Integer.toString(countSelected) + " " + getString(R.string.selectItem));
        }

问题是:当我长按项目(例如,第一项)时,第 7 项也突出显示(通过更改背景)。当我尝试“取消突出显示”突出显示的第 7 项时,应用程序崩溃。如果我尝试单击最新项目,应用程序会崩溃。我已经阅读了一些关于如何渲染视图和回收项目的文章,但我不知道我的问题有任何可能的解决方案

UPD:“取消突出显示”第 7 项时的 LogCat 输出:

    V/checked?(24966): YES
V/Position(24966): 7
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x2b542210)
AndroidRuntime(24966): FATAL EXCEPTION: main
java.lang.NullPointerException
at com.alextee.phrases.PhraseActivity$1.onItemCheckedStateChanged(PhraseActivity.java:145)
at android.widget.AbsListView$MultiChoiceModeWrapper.onItemCheckedStateChanged(AbsListView.java:5688)
at android.widget.AbsListView.performItemClick(AbsListView.java:1040)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:2522)
at android.widget.AbsListView$1.run(AbsListView.java:3183)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
 android.app.ActivityThread.main(ActivityThread.java:4441)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
4

2 回答 2

10

列表视图本身很复杂,它的回收也很复杂。如果您观看列表视图的 android 开发人员视频,您将了解更多有关列表视图回收及其问题的信息。
您的应用程序中的问题是由于列表视图回收。
当您在单击或长按时更改列表项的背景时,它的背景会发生变化,并且当该项目滚动出设备的可见区域时,该项目所附的视图将被回收,并将其分配给其他一些列表项当前可见。所以现在该项目也将突出显示。
这张图描述了列表视图回收:

在此处输入图像描述


要突出显示列表视图中的项目,您应该执行以下操作:

  • 在列表视图上设置 onItemClickListener。
  • 在 onItemClick() 方法中更改视图的背景并将当前突出显示的位置保存在列表视图中,并在列表适配器上调用 notifyDataSetChanged()。调用 notifyDataSetChanged() 很重要,因为它会重绘当前可见项。

列表 onItemClick 的代码应该是这样的:

grid[pos].setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick (AdapterView<?> parent,
                    View v, int position, long Id)
            {
                    highlighted = position;    //highlighted is a global variable
                    //container is the root view of the list row layout
                    LinearLayout container = (LinearLayout)v.findViewById(R.id.container);
                    container.setBackgroundResource(R.drawable.highlighted_backg);
                    mListAdapter.notifyDataSetChanged();

            }
   });

getView() 方法应该这样实现:

public View getView (int position, View convertView, ViewGroup parent)
{
    ViewHolder holder;

    if(convertView == null) {
        convertView = inflater.inflate(R.layout.row_item, null);
        holder = new ViewHolder();
        holder.itemName1 = (TextView)convertView.findViewById(R.id.text1);
        ...
        holder.container = (LineaLayout)convertView.findViewById(R.id.container);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    if(MainActivity.highlighted == position) {
        holder.container.setBackgroundResource(R.drawable.highlighted_backg);
    }else {
        holder.foodItemCol1.setBackgroundResource(R.drawable.normal_back);
    }

    return convertView;
}
于 2012-08-19T13:28:44.750 回答
1

getView()根据项目的选中状态设置项目的背景颜色。我不知道您是否可以直接从 ListView 中获取此信息,否则您可以保留例如 aSet并将当前选中的位置保留在那里。然后getView()查找传递的位置是否在此集合中,这意味着它已被检查并相应地设置背景。如果不是,请将背景设置为未选中的颜色。后一个很重要,因为您可能已经获得了一个背景设置为“已检查”颜色的回收视图。

可以在此处找到跟踪检查项目的示例。

于 2012-08-19T13:25:25.777 回答