I have a ListFragment
with a SimpleCursorAdapter
and want to set a longClickListener
to each of the items
in the list
i.e. to one of the TextViews
in each item.
So I need to Access the TextView
to call setOnLongClickListener
on that view.
The ListFragment
(where I always get null from findViewById
but would like to use the setOnLongClickListener
):
public class OverviewFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
...
@Override
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle b ) {
View fragView = inflater.inflate( R.layout.overview_fragment, container, false );
return fragView;
}
@Override
public void onActivityCreated( Bundle state ) {
super.onActivityCreated (state );
getLoaderManager().initLoader( LOADER_ID_READ_OVERVIEW, null, this );
adapter = new SimpleCursorAdapter( getActivity(), R.layout.overview_row, null, overviewDbColumns, overviewTargetViewIds, 0 );
setListAdapter( adapter );
TextView tv = (TextView) getListView().findViewById( R.id.overviewFooName );
if ( tv == null ) { //is always null!!!
Log.e( TAG, "OverviewFragment->onActivityCreated: tv == null" );
} else {
tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if ( mActionMode != null ) {
return false;
}
mActionMode = getActivity().startActionMode(mActionModeCallback);
view.setSelected(true);
return true;
}
});
}
}
The overview_fragment.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="@android:layout/list_content" />
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:choiceMode="singleChoice" >
</ListView>
<TextView
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/no_foo_in_list"
/>
and the overview_row.xml (used by tha SimpleCursorAdapter
):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/overviewFooName"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="fill_parent" />
<TextView
android:id="@+id/overviewFooType"
android:layout_width="wrap_content"
android:layout_height="26dp" />
<TextView
android:id="@+id/overviewFooDbIndex"
android:layout_width="wrap_content"
android:layout_height="26dp" />
My idea of how android uses the view hierarchy seems to be wrong. My idea is that of one single tree, where I can access every node - as long as I know its ID - from any other node that is nearer to the root. Is this right?
If this idea is wrong, as I expect - how do I get access to the TextView (or the whole item)?
And where do I place the code for the mActionModeCallback
?
Without having tried this myself I suppose that the problem here is that the ID you are giving to findViewById (R.id.overViewFooName) is ambiguous: Since every list item contains a TextView with this ID, how should the framework decide, which of these to return in findViewById?
So, I think you have two options:
That is, you set a OnItemLongClickListener on the whole ListView - it has a method:
public abstract boolean onItemLongClick (AdapterView<?> parent, View view, int position, long id)
which will be called whenever an item in the ListView is long-clicked. As you can see, the method also receives the position of the long-clicked item and you can then handle the click accordingly.
If you really need to have just the TextView within each item long-clickable (and not the whole item as in solution 1.), you would need to set the listener in the getView-method of the adapter that creates the list item views.
That is, you subclass SimpleCursorAdapter and overwrite the getView method. There you inflate your XML layout, get a reference to the TextView and set the OnLongClickListener. In this case, since you are doing this for each item seperately, the findViewById will work because you are in a subtree of the view tree where there is indeed only one View with the ID R.id.overViewFooName.