1

私は ExpandableListView を持っています。各子には CheckBox と TextView があります。ユーザーが子行をタップすると、CheckBox はその状態 (チェック済みとチェックなし) を変更することになっています。ユーザーがチェック ボックスを直接タップすると、これは正しく機能します。ただし、ユーザーがテキスト ビュー (同じ行、チェック ボックスのすぐ右) をタップすると、チェック ボックスを参照しようとするとすぐに null ポインター エラーが発生します。誰が何が間違っているかを見ることができますか?

編集: 以下の提案を読んだ後、いくつかの調査を行い、getChildView() の下のアダプター内に clickListener を実装できることに気付きました。これにより、子ビューへの参照を簡単に取得できるため、null ポインターに関する問題が解決されます。

ただし、これにより、エレガントな解決策が見当たらない別の問題が発生します。子がクリックされるたびに、リストビュー自体を変更する必要があります。このリストのデータは、スコープが (アダプタではなく) アクティビティ内にある ArrayList に存在します。clickListener が Adapter にある場合、Activity にコールバックして ArrayList を変更するにはどうすればよいですか?

これはキャッチ22のように私を襲います。データを操作できるようにしたい場合、子ビューへの参照を取得できません。しかし、子ビューへの参照が必要な場合、データは範囲外であるため、操作できません。人々はこれをどのように解決しますか?私は何かが欠けているに違いない。

子 onClickListener を追加しようとする私の試みの始まりを確認できる関連するアダプター コードを挿入します。

再度、感謝します!

    public class Settings extends Activity {

        //this is the list I need to access from the adapter if my click listener is there
        private ArrayList<Categories> categoriesList = null;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_smart_settings);

            db = new EventsDB(this);

            expListGroups = new ArrayList<ExpandListGroup>();
            setGroups();

            /* Set up the data adapter */
            expAdapter = new ExpandListAdapter(Settings.this, expListGroups);

            populateExpandableGroups();

        }

        public void setGroups() {

            /* Create lists of the individual line items */
            categoriesList = db.getCategoriesForClient(client);
            locationsList = db.getLocationsForClient(client);

            /* Add an item to the locations list to allow the user to add a new location */
            locationsList.add(new ClientSmartFinderLocations(client, "Add Location", null, false));

            ExpandListGroup categoryGroup = new ExpandListCategory("Choose Categories", categoriesList);
            ExpandListGroup locationGroup = new ExpandListLocation("Choose Locations", locationsList);

            expListGroups.add(categoryGroup);
            expListGroups.add(locationGroup);

        }

        private void populateExpandableGroups() {
            expandableList = (ExpandableListView) findViewById(R.id.expandable_list);
            expandableList.setAdapter(expAdapter);

            //I've removed this section and moved it to the adapter, per my edit above
//            expandableList.setOnChildClickListener(new OnChildClickListener() {
//            
//                @Override
//                public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
//                  
//                  /* Update the finder setting for this client */
//                  String category = categoriesList.get(childPosition).getCategory();
//                  Boolean isSelected = !categoriesList.get(childPosition).getIsSelected();
//                  db.setClientCategory(client, category, isSelected);
//          
//                  /* Update the check box to provide feedback to the user */
//                  View view = parent.getChildAt(childPosition - parent.getFirstVisiblePosition() + 1);
//                  CheckBox checkBox = (CheckBox) view.findViewById(R.id.check_box);
//
//                        //error occurs here
//                  checkBox.setChecked(!checkBox.isChecked());
//                            return true;
//                }
//            });

            expAdapter.notifyDataSetChanged();
        }




public class ExpandListAdapter extends BaseExpandableListAdapter {

    //other methods

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, final ViewGroup parent) {


            view = getCategoryChildView(groupPosition, childPosition, view);

            view.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {

                    TextView tv = (TextView) v.findViewById(R.id.expand_list_item);
                    CheckBox checkBox = (CheckBox) v.findViewById(R.id.check_box);

                    String category = tv.getText().toString();
                    Boolean isSelected = !checkBox.isSelected();

                    db = new EventsDB(context);
                    db.setClientCategory(client, category, isSelected);

                    checkBox.setChecked(!checkBox.isChecked());

                    //here I need to do some things that require me to manipulate the categoriesList from the Activity class - but it is out of scope
                }
            });

        return view;
    }
}

<CheckBox
    android:id="@+id/check_box"
    android:layout_marginLeft="30dp"
    android:focusable="false"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/expand_list_item"
    android:paddingLeft="10dp"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="@dimen/smart_finder_settings_font_size"
    android:textColor="#FFFFFF" />

4

4 に答える 4

1

私は解決策を持っていると思います。Adapter 内に Settings アクティビティ クラスのインスタンスを作成すると、通常の getter/setter メソッドを Settings クラスに追加できます。その後、アダプタからこれらのメソッドを呼び出して、そのリストを取得し、変更してから、Settings クラスにプッシュすることができます。すべてがうまくいくはずです。

これは基本的な OOP アプローチですが、私にとっての精神的な問題は、アクティビティをインスタンス化するというアイデアでした。これが一般的かどうかはわかりませんが、私には奇妙に思えます。誰もがよりエレガントなソリューションを持っていますか?

設定クラス内:

public ArrayList<Categories> getCategoriesList() {
    return categoriesList;
}

public void setCategoriesList(ArrayList<Categories> list) {
    categoriesList = list;
}

アダプター内:

Settings settings = new Settings();
ArrayList<Categories> tempCategoriesList = new ArrayList<Categories>();
tempCategoriesList = settings.getCategoriesList();
//make changes to the list
settings.setCategoriesList(tempCategoriesList);
于 2013-06-14T06:01:11.647 に答える
0

私はプロではないので、それを念頭に置いてください。しかし、グローバル アプリケーション クラスで操作するために clicklistener が必要とするデータを格納する場合はどうでしょうか? おそらく最もエレガントではないかもしれませんが、うまくいくかもしれません。

于 2013-12-31T22:13:36.930 に答える
0

ExpandListAdapter内部のビューに直接アクセスするのではなく、内部でチェックボックスのチェック状態を設定する必要がありますExpandableListView

于 2013-06-12T23:22:34.393 に答える