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番目のアイテムを「ハイライト解除」しようとすると、アプリがクラッシュします。最新のアイテムをクリックしようとすると、アプリがクラッシュします。Viewのレンダリング方法とアイテムのリサイクル方法に関する記事をいくつか読みましたが、問題の解決策がわかりません。

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 に答える