10

次のように、カスタムアダプタを使用するListViewがあります。

private class CBAdapter extends BaseAdapter implements OnCheckedChangeListener{

    Context context;
    public String[] englishNames;
    LayoutInflater inflater;
    CheckBox[] checkBoxArray;
    LinearLayout[] viewArray;
    private boolean[] checked;

    public CBAdapter(Context con, String[] engNames){
        context=con;
        englishNames=engNames;
        inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        checked= new boolean[englishNames.length];
        for(int i=0; i<checked.length; i++){
            checked[i]=false;
            //Toast.makeText(con, checked.toString(),Toast.LENGTH_SHORT).show();
        }
        checkBoxArray = new CheckBox[checked.length];
        viewArray = new LinearLayout[checked.length];
    }

    public int getCount() {
        return englishNames.length;
    }

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

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

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

        if(viewArray[position] == null){

            viewArray[position]=(LinearLayout)inflater.inflate(R.layout.record_view_start,null);

            TextView tv=(TextView)viewArray[position].findViewById(R.id.engName);
            tv.setText(englishNames[position]);

            checkBoxArray[position]=(CheckBox)viewArray[position].findViewById(R.id.checkBox1);
        }

        checkBoxArray[position].setChecked(checked[position]);
        checkBoxArray[position].setOnCheckedChangeListener(this);
        return viewArray[position];
    }


    public void checkAll(boolean areChecked){
        for(int i=0; i<checked.length; i++){
            checked[i]=areChecked;
            if(checkBoxArray[i] != null)
                checkBoxArray[i].setChecked(areChecked);
        }
        notifyDataSetChanged();
    }

    public void onCheckedChanged(CompoundButton cb, boolean isChecked) {
        for(int i=0; i<checked.length; i++){
            if(cb == checkBoxArray[i])
                checked[i]=isChecked;
        }




    }
    public boolean itemIsChecked(int i){
        return checked[i];
    }

}

レイアウトはかなりシンプルなので、誰かが関連性があると思わない限り、私はそれらを投稿しません。

問題は、一部のチェックボックスが応答しないことです。レイアウトを最初に表示したときに見えるもののようです。期待どおりに機能するために下にスクロールする必要があるもの。

どんなポインタでもありがたいです。

4

3 に答える 3

16

回答からのコードは機能しますが、非効率的です(実際にこれを確認できます。スクロールして、ListViewをチェックしLogcat、ガベージコレクターが機能していることを確認してください)。ビューをリサイクルする改善されたgetView方法は次のとおりです。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
     LinearLayout view = (LinearLayout) convertView;
     if (view == null) {
          view = (LinearLayout) inflater.inflate(R.layout.record_view_start, parent, false);
     }
     TextView tv = (TextView) view.findViewById(R.id.engName);
     tv.setText(getItem(position));
     CheckBox cBox = (CheckBox) view.findViewById(R.id.checkBox1);
     cBox.setTag(Integer.valueOf(position)); // set the tag so we can identify the correct row in the listener
     cBox.setChecked(mChecked[position]); // set the status as we stored it        
     cBox.setOnCheckedChangeListener(mListener); // set the listener    
     return view;
}

OnCheckedChangeListener mListener = new OnCheckedChangeListener() {

     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {   
         mChecked[(Integer)buttonView.getTag()] = isChecked; // get the tag so we know the row and store the status 
     }
};

質問からのコードに関しては、最初は行の設定方法が原因で間違っていると思いましたが、行ビューをリストから切り離したときにアダプターがその動作をする理由がわかりません。また、私はコードをテストしましたが、それは非常にうまく機能しますCheckBoxes(ただし、メモリ処理は非常に貧弱です)。アダプターが機能しないようにする何か他のことをしているのではないでしょうか。

于 2012-10-31T15:34:59.000 に答える
1

最初に、アダプタを使用する主な利点の1つである再利用可能なビューを破棄したと言います。作成されたそれぞれへのハードリファレンスをView保持すると、メモリの上限に達するリスクが高くなります。nullでない場合は再利用しconvertView、nullの場合はビューを作成する必要がconvertViewあります。これを行う方法を示す多くのチュートリアルがあります。

アダプタで使用されるビューには通常OnClickListener、親によってアタッチされているため、にViewを設定できます。これは、個々のビューのタッチリスナーに優先します。XMLで設定してみてください。OnItemClickListenerListViewandroid:clickable="true"CheckBox

于 2012-09-28T20:41:57.907 に答える
0

これは最もエレガントで効率的な解決策ではないかもしれませんが、私の状況では機能します。何らかの理由で、ビューの配列から、またはconvertViewを使用してビューを再利用しようとすると、すべてが不安定になり、チェックボックスが応答しなくなります。

動作したのは、getView()が呼び出されるたびに新しいビューを作成することだけでした。

    public View getView(final int position, View convertView, ViewGroup parent) {
        LinearLayout view;
        view=(LinearLayout)inflater.inflate(R.layout.record_view_start,null);


        TextView tv=(TextView)view.findViewById(R.id.engName);
        tv.setText(englishNames[position]);

        CheckBox cBox=(CheckBox)view.findViewById(R.id.checkBox1);
        cBox.setChecked(checked[position]);
        cBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){

            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                checked[position]=isChecked;
            }
        });
        return view;
    }

このソリューションを見つけることは、個別に定義されたonCheckedChangedListenerを呼び出していたため、各CheckBoxに新しいリスナーを設定するのではなく、IDによってどのCheckBoxを識別したかによっても妨げられました。

まだ、これを正解としてマークしていません。毎回ビューを再構築するのはかなり無駄なことについて、他の人が何らかの意見を持ってくれることを期待しているからです。

于 2012-10-05T07:46:33.240 に答える