I have custom rows for the ListView hosted in my navigation drawer, everything worked fine when I only had a simple TextView for each row.
I decided then to add two ImageButtons for each row, displaying EDIT and DISCARD ImageButtons, the problem in this case is that ImageButtons steal focus and the ListView Adapter onItemClickListener no longer receives onItemClick event, so the content of the main fragment can't change accordingly to which element i click on the drawer.
I use a custom CursorAdapter to populate the ListView of the drawer, so I decided to create an OnClickListener for each element of the row. Every single item of the row now correcly reacts to click events...The problem now is I can't trasmit the onClick event from the TextView element to the ListView in order to correctly select the item in the ListView.
custom_list_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:clickable="true">
<ImageButton
android:id="@+id/drawer_list_item_discard"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_discard"
android:scaleType="centerCrop"
android:layout_alignParentRight="true"
android:background="@null"
android:padding="0dp"/>
<ImageButton
android:id="@+id/drawer_list_item_edit"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_edit"
android:scaleType="centerCrop"
android:padding="0dp"
android:background="@null"
android:layout_toLeftOf="@id/drawer_list_item_discard"/>
<TextView
android:id="@+id/drawer_list_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_centerInParent="true"
android:textColor="#000000"
android:textSize="20dp"
android:layout_toLeftOf="@id/drawer_list_item_edit"
android:layout_alignParentLeft="true" />
</RelativeLayout>
bindView(...) inside ProgramsCursorAdapter.java:
@Override
public void bindView(View v, Context context, Cursor c) {
if (mContext == null) return;
// Instances of the Views
TextView tv_name = (TextView) v.findViewById(R.id.drawer_list_item_text);
// Override fonts
Typeface robotoLight = Typeface.createFromAsset(mContext.getAssets(), "fonts/Roboto-Light.ttf");
if (tv_name != null) tv_name.setTypeface(robotoLight);
// Retrieve values of the row
String name = c.getString(c.getColumnIndex(DBHelper.TB_PROGRAM_NAME));
// Assign retrieved value to the row
tv_name.setText(name);
tv_name.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("Program click!");
}
});
//Set up imagebuttons
ImageButton edit = (ImageButton) v.findViewById(R.id.drawer_list_item_edit);
edit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("Edit onclick!");
}
});
ImageButton discard = (ImageButton) v.findViewById(R.id.drawer_list_item_discard);
discard.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("Discard onclick!");
}
});
}
I saw a few post also here in SO about the problem I'm facing in this moment but no one could figure out how to solve it, I think I'm on the good way but I still can't get it done right. Thanks in advance.
Finally got it working, in case someone else needs this. I think that's the only possible workaround...
I added an interface
public interface NavigationDrawerListHandler {
/**
* Called when an item in the navigation drawer is selected.
*/
void selectItem(int position);
}
either NavigationDrawerFragment
and ProgramsCursorAdapter
implement NavigationDrawerListHandler
.
ProgramsCursorAdapter
also keeps a reference of the type NavigationDrawerListHandler
which is passed to it by the method
ProgramsCursorAdapter.java
public void attach(NavigationDrawerFragment f) {
try {
mCallbacks = (NavigationDrawerListHandler) f;
} catch (ClassCastException e) {
throw new ClassCastException(
"Fragment must implement NavigationDrawerListHandler.");
}
}
which is called when a new instance of ProgramsCursorAdapter
is bound to the drawer's ListView like this:
NavigationDrawerFragment.java
// Set up adapter and bind it to the list
ProgramsCursorAdapter adapter = new ProgramsCursorAdapter(getActionBar()
.getThemedContext(), database.getPrograms(), CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
mDrawerListView.setAdapter(adapter);
// Attach this fragment to the adapter
adapter.attach(this);
this way the adapter has direct access to the setItem(int position) method that belongs to NavigationDrawerFragment and can call setItem(int position) from the onClick(View v) like this:
ProgramsCursorAdapter.java
@Override
public void bindView(View v, Context context, Cursor c) {
/* ... */
// Get the position of the clicked view
final int p = c.getPosition();
tv_name.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("Program click!");
selectItem(p);
}
});
/* ... */
}
@Override
public void selectItem(int position) {
mCallbacks.selectItem(position);
}
Hope that this will help!