ExpandableListView onChildClick 不触发(在 master/detail 流程中)

ExpandableListView onChildClick doesn't fire (in master/detail flow)

我知道很多人都问过类似的问题,但是 none 他们的解决方案对我有用。

我有一个 master/detail 流 expandable list 作为 list。我可以单击组并展开它们,但是 我无法单击 children.

我已将它们设置为可选(起初我认为这是问题所在),它们上面没有任何 checkboxes 或图像,只有纯文本。我什至将该文本设置为不是 focusable(因为可聚焦元素似乎是其他人的问题)。

这是我拥有的: 自定义 BaseExpandableAdapter:

public class CabinetAndRacksExpandAdapter extends BaseExpandableListAdapter {
//(some fields that probably aren't relevant)
@Override
public int getGroupCount() {
        return cabinets.size();
    }
(more override methods here, probably not relevant)

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.listrow_cabinet, null);
    }
    Cabinet cabinet = (Cabinet) getGroup(groupPosition);
    ((CheckedTextView) convertView).setText(cabinet.toString());
    ((CheckedTextView) convertView).setChecked(isExpanded);
    return convertView;
    }

@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
    final Rack rack = (Rack) getChild(groupPosition, childPosition);

    TextView text = null;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.listrow_rack, null);
    }
    final View view = convertView;
    text = (TextView) convertView.findViewById(R.id.textView1);
    text.setText(rack.toString());
    return convertView;
   }

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true;
    }
}

我还有一个fragment(master/detail流程中的列表片段)。它应该监听 child 和组的点击,所以它实现了那些 listeners:

public class CabinetListFragment extends Fragment implements ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupClickListener{
    //(some stuff that's probably not relevant)

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_cabinet_list, container, false);

        listView = (ExpandableListView) rootView;
        listView.setOnChildClickListener(this);
        listView.setOnGroupClickListener(this);

        Bundle extras = getActivity().getIntent().getExtras();
        if(extras != null)
        {
            String orderId = extras.getString(CabinetListActivity.ARG_ORDER_ID);
            order = service.getOrderFromId(service.intFromString(orderId));
        }
        CabinetAndRacksExpandAdapter adapter = new CabinetAndRacksExpandAdapter(getActivity(), service.getCabinetsForOrder(order));
        listView.setAdapter(adapter);

        return rootView;
    }

 @Override
 public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
        Log.d("CabinetListFragment", "onChildClick");
        mCallbacks.onChildSelected(groupPosition, childPosition);
        return true;
    }

 @Override
 public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id)
    {
        Log.d("CabinetListFragment", "onGroupClick");
        mCallbacks.onGroupSelected(groupPosition);
        return false;
    }

/**
 * A callback interface that all activities containing this fragment must
 * implement. This mechanism allows activities to be notified of item
 * selections.
 */
public interface Callbacks {
    /**
         * Callback for when an item has been selected.
         */
        public void onChildSelected(int groupPosition, int childPosition);
        public void onGroupSelected(int groupPosition);
    }

@Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Activities containing this fragment must implement its callbacks.
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException("Activity must implement fragment's callbacks.");
        }

        mCallbacks = (Callbacks) activity;
    }
}

此片段属于 Activity,它按应有的方式实现了回调:

public class CabinetListActivity extends FragmentActivity
    implements CabinetListFragment.Callbacks{

/**
 * Whether or not the activity is in two-pane mode, i.e. running on a tablet
 * device.
 */
private boolean mTwoPane;

public static final String ARG_ORDER_ID = "order_id";
private Service service;
private Order order;
private String orderId;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_cabinet_list);
    service = Service.getInstance();

    if (findViewById(R.id.cabinet_detail_container) != null) {
        mTwoPane = true;
    }

    Bundle extras = getIntent().getExtras();
    if(extras != null)
    {
        String orderId = extras.getString(ARG_ORDER_ID);
        order = service.getOrderFromId(service.intFromString(orderId));
        this.orderId = orderId;
    }
}

/**
 * Callback method from {@link CabinetListFragment.Callbacks}
 * indicating which item was selected.
 */
@Override
public void onChildSelected(int groupPosition, int childPosition) {
    if (mTwoPane) {
        // In two-pane mode, show the detail view in this activity by
        // adding or replacing the detail fragment using a
        // fragment transaction.
        Bundle arguments = new Bundle();
        arguments.putString(CabinetDetailFragment.ARG_CHILD_ID, childPosition+"");
        arguments.putString(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
        arguments.putBoolean(CabinetDetailFragment.ARG_RACKMODE, true);
        CabinetDetailFragment fragment = new CabinetDetailFragment();
        fragment.setArguments(arguments);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.cabinet_detail_container, fragment)
                .commit();

    } else {
        // In single-pane mode, simply start the detail activity
        // for the selected item ID.
        Log.d("CabinetListActivity", "show rack");
        Intent detailIntent = new Intent(this, CabinetDetailActivity.class);
        detailIntent.putExtra(CabinetDetailFragment.ARG_CHILD_ID, childPosition + "");
        detailIntent.putExtra(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
        detailIntent.putExtra(CabinetDetailFragment.ARG_RACKMODE, true);
        startActivity(detailIntent);
    }
}

@Override
public void onGroupSelected(int groupPosition) {
    if (mTwoPane) {
        // In two-pane mode, show the detail view in this activity by
        // adding or replacing the detail fragment using a
        // fragment transaction.
        Bundle arguments = new Bundle();
        arguments.putString(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
        arguments.putString(CabinetDetailFragment.ARG_ORDER_ID, orderId);
        arguments.putBoolean(CabinetDetailFragment.ARG_RACKMODE, false);
        CabinetDetailFragment fragment = new CabinetDetailFragment();
        fragment.setArguments(arguments);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.cabinet_detail_container, fragment)
                .commit();
    } else {
        // In single-pane mode, simply start the detail activity
        // for the selected item ID.
        Intent detailIntent = new Intent(this, CabinetDetailActivity.class);
        detailIntent.putExtra(CabinetDetailFragment.ARG_GROUP_ID, groupPosition+"");
        detailIntent.putExtra(CabinetDetailFragment.ARG_ORDER_ID, orderId);
        detailIntent.putExtra(CabinetDetailFragment.ARG_RACKMODE, false);
        startActivity(detailIntent);
        }

    }
//(more stuff that's probably not relevant)
}

我看不出我的 childClick 事件与 GroupClick 事件有何不同。 如前所述,GroupClick 触发并按预期处理,但 childClick 甚至没有触发(我已经尝试从片段中的 onChildClick 登录)。 顺便说一句,该方法 return 是真还是假似乎没有任何区别(自然地,因为它从未被调用过)。

我试过直接在 childView 上创建一个侦听器,这很有效。但是我需要在片段或 activity(最好是 activity(最好是 activity,但它应该是监听事件的片段)中做一些事情,这样就不行了。

为什么我的 fragment 在注册为 listener 时没有收到 onChildClick 事件的通知?该事件是否由于某种原因从未被解雇过?还是在别处处理?

也许,你正在尝试做的是类似这样的事情:

public class FaltasFragmentActivity extends Activity {

    //Lista de faltas
    private ExpandableListView mExpandalbeView;
    private ExpandableListAdapter listAdapter; 
    private int posicion;

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

        mExpandalbeView = (ExpandableListView) findViewById(R.id.expandable_faltas);

        mExpandalbeView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            @Override
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                // Codigo para cerra el ultiom grupo abierto antes de abrir el nuevo
                Toast.makeText(FaltasFragmentActivity.this, "pulsado group: " + groupPosition, Toast.LENGTH_SHORT).show();
                return false;
            }
        });

        // Listview on child click listener
        mExpandalbeView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                                        int groupPosition, int childPosition, long id) {
                Toast.makeText(FaltasFragmentActivity.this, "pulsado child: (" + groupPosition + ", " + childPosition + ")", Toast.LENGTH_SHORT).show();
                return false;
            }
        });

        // Listview Group expanded listener
        mExpandalbeView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                Toast.makeText(FaltasFragmentActivity.this, "pulsado expand", Toast.LENGTH_SHORT).show();
            }
        });

        // Listview Group collasped listener
        mExpandalbeView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
            @Override
            public void onGroupCollapse(int groupPosition) {
                Toast.makeText(FaltasFragmentActivity.this, "pulsado collapse", Toast.LENGTH_SHORT).show();
            }
        });

        listAdapter = new ExpandableListAdapter(FaltasFragmentActivity.this, root, posicion, filtroBusqueda);
        mExpandalbeView.setAdapter(listAdapter);
    }
}

其中 ExpandableListAdapter(...) 是:

public class ExpandableListAdapter extends BaseExpandableListAdapter{...}

这对我有用! 希望这对您有所帮助!

只是瞎猜,但是你在那些不相关的方法中实现了吗

int getChildrenCount(int groupPosition) {
  // Return whatever the children's count is
}

public boolean areAllItemsEnabled() {
  return true;
}

在布局 XML R.layout.listrow_rack 中,您有没有禁用该项目,或者关联一个静默触发的点击侦听器?

好的,这就是问题所在:

这是我的 listrow_rack:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="40dp"
android:clickable="true"
android:orientation="vertical"
android:paddingLeft="40dp"
tools:context=".OrdreDetailActivity" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawablePadding="5dp"
    android:gravity="center_vertical"
    android:text="@string/hello_world"
    android:textSize="14sp"
    android:textStyle="bold">
</TextView>

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@android:color/black" />

问题出在这一行:

    android:clickable="true"

我不确定为什么,但也许它添加了一个侦听器,或者可能出于其他原因。但是当我删除它时,它起作用了。

支持 Andras Baláz Lathja 为我指明了正确的方向。