Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Listview is not responding to the click event

As you would guess everything loads fine, no click event get triggered. Before I start I have read so many thread about this however I for the life of me I cant figure it out. Here is the code.

activity_main.xml (Main Layout to call the list)

<LinearLayout
    android:orientation="vertical" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

     <ListView
         android:id="@android:id/list"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"

         />

</LinearLayout>

list_mainsegments_row.xml (Custom Row)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:orientation="horizontal" 
        >

        <ImageView
            android:id="@+id/iconView"
            style="@style/generalPagesLogoStyle"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_margin="@dimen/tendpPadding"
            android:scaleType="fitCenter"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:id="@+id/titleMainSegments"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left|center_vertical"
            android:layout_weight="0.5"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textSize="@dimen/generalTextSize"
             />

        <ImageButton
            android:id="@+id/imageButton1"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_gravity="center_vertical"
            android:scaleType="fitCenter"
            android:src="@drawable/arrow" />
    </LinearLayout>

MyAdapter.java

   public class MyAdapter extends ArrayAdapter<String> {

    public MyAdapter(Context context, int resource, int textViewResourceId,
            String[] strings) {
        super(context, resource, textViewResourceId, strings);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = LayoutInflater.from(getContext());
        // This is a single row
        View row = inflater.inflate(R.layout.list_mainsegments_row, parent,
                false);
        String[] items = getContext().getResources().getStringArray(
                R.array.segments_main);
        ImageView iv = (ImageView) row.findViewById(R.id.iconView);
        TextView tv = (TextView) row.findViewById(R.id.titleMainSegments);
        tv.setText(items[position]);
        organiseLayout(position, items, iv);
        return row;

    }

    private void organiseLayout(int position, String[] items, ImageView iv) {
        if (items[position].equals(getContext().getResources().getString(
                R.string.segment_one))) {
            iv.setImageResource(R.drawable.img1);
        }
        if (items[position].equals(getContext().getResources().getString(
                R.string.segment_two))) {
            iv.setImageResource(R.drawable.img2);
        }
    }
}

MainActivity.java

public class MainActivity extends ListActivity implements OnItemClickListener {

private MyAdapter mAdapter;

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

    mAdapter = new MyAdapter(this, android.R.layout.simple_list_item_1,
            R.id.titleMainSegments, getResources().getStringArray(
                    R.array.segments_main));

    setListAdapter(mAdapter);
    getListView().setOnItemClickListener(this);

}

public void onItemClick(AdapterView<?> parent, View view,
        int position, long id) {
    CharSequence text = "Item clicked";
    int duration = Toast.LENGTH_SHORT;
    Toast toast = Toast.makeText(this, text, duration);
    toast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL,
            duration, duration);
    toast.show();
} }

There is no error so the logCat log is not going to be useful. All comes up well but no Toast is showing when ListView is tapped.

Edit:

style.xml:

<!-- Global styles -->
    <style name="horizLayoutHolder">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_gravity">center_horizontal</item>
    </style>

    <!-- This is for the text based pages -->
    <style name="general_pages">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">fill_parent</item>
        <item name="android:orientation">vertical</item>
        <item name="android:paddingBottom">@dimen/generalPadding</item>
        <item name="android:paddingLeft">@dimen/generalPadding</item>
        <item name="android:paddingRight">@dimen/generalPadding</item>
        <item name="android:paddingTop">@dimen/tendpPadding</item>
    </style>

    <style name="generalPagesTitleStyle">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginBottom">@dimen/tendpPadding</item>
        <item name="android:textColor">#000</item>
        <item name="android:textSize">@dimen/generalHeadingTextSize</item>
        <item name="android:textStyle">bold</item>
    </style>

    <style name="generalPageScrollView">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <style name="generalPageMainText">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">#000</item>
        <item name="android:textSize">@dimen/generalSmallFontSize</item>
    </style>

    <style name="generalPagesLogoStyle">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:layout_marginBottom">@dimen/tendpPadding</item>
"                <item name="android:src">@drawable/mainlogo</item>
    </style>

    <style name="generalActionButton">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">40dp</item>
        <item name="android:layout_gravity">center_horizontal</item>
        <item name="android:textSize">@dimen/generalVerySmallFontSize</item>
        <item name="android:paddingRight">@dimen/generalPadding</item>
        <item name="android:paddingLeft">@dimen/generalPadding</item>
    </style>

    <style name="generalTextBoxes">
        <item name="android:layout_width">250dp</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:layout_gravity">center_horizontal</item>
        <item name="android:ems">10</item>
        <item name="android:textSize">@dimen/generalSmallFontSize</item>
    </style>

    <!-- End of General / Full text based activities -->


    <!-- I have used this in theme.xml -->
    <style name="windowTitleBackgroundStyle">
        <item name="android:background">#CCCCCC</item>
    </style>

    <style name="windowTitleStyle">
        <item name="android:textColor">#000000</item>
        <item name="android:padding">12dip</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textSize">16sp</item>
    </style>
    <!-- End of Theme.xml stuff -->

themes.xml

<style name="Theme.myTheme.TitleBar" parent="android:Theme">
    <item name="android:windowTitleBackgroundStyle">@style/windowTitleBackgroundStyle</item>
    <item name="android:windowTitleStyle">@style/windowTitleStyle</item>
    <item name="android:windowTitleSize">50dip</item>
    <item name="android:background">#F8C845</item>
    <item name="android:textColor">#555</item>
</style>
like image 328
Mr H Avatar asked Dec 16 '22 15:12

Mr H


1 Answers

Remove the LinearLayout attribute

android:clickable="true"

from the XML file list_mainsegments_row.xml and it should work fine (I have just tried it).


EDIT

When you use the setOnItemClickListener method of the ListView having childs that contain a Button/ImageButton, the method is never fired because the Button/ImageButton consumes the event.

The solution is to use setOnClickListener (for every item) instead of setOnItemClickListener (for the ListView).

In order to do that, you can pass the OnClickListener to the adapter in the following manner :

The adapter should be as follows :

private OnClickListener callback;

public class MyAdapter extends ArrayAdapter<String> {

public MyAdapter(Context context, int resource, int textViewResourceId,
        String[] strings ,  OnClickListener callback ) {
    super(context, resource, textViewResourceId, strings);
    this.callback = callback;
}

And in the getView method, just add the following lines that set the click listener, after inflating the row view :

// Set a click listener on the row itself
row.setOnClickListener ( callback );
// Set the position as tag so it can be retrieved from the click listener because the click listener itself does not provide the position like done in the onItemClickListener
row.setTag ( position );

And now, the MainActivity should implement OnClickListener instead of OnItemClickListener, so remove the method onItemClick and also remove the following statement from the onCreate method :

getListView().setOnItemClickListener(this);

And add the following method :

@Override
public void onClick ( View view ) {
        // view is the row view returned by getView
        // The position is stored as tag, so it can be retrieved using getTag ()
    CharSequence text = "Item clicked : " + view.getTag () ;
    int duration = Toast.LENGTH_SHORT;
    Toast toast = Toast.makeText(this, text, duration);
    toast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL,
            duration, duration);
    toast.show();
}

And finally, declare the Adapter in the following manner :

    mAdapter = new MyAdapter(this, android.R.layout.simple_list_item_1,
            R.id.titleMainSegments, getResources().getStringArray(
                    R.array.segments_main) , this );

EDIT

Explanation :

What happened with you is a common issue that occurs when you have a ListView with items that contain buttons (or the like).

In this case, if you want to have a click event for the button alone, and another click event for the rest of the item (if the user clicks in the item but not on the button), this is where the problem hits : the botton consumes the clickable attribute of the item, meaning that if the item does not contain any buttons it will be clickable by default (you can try to remove the button) but if the item contains a button, it will be clickable because it has a view that itself is clickable.

Therefore, even if you set the OnItemClick event, it will NOT be called if the item HAS a button (or something similar, like an image button) in it, because it (the button) will consume the click event.

So in this case you cannot use the OnItemClick event (which is assigned on the ListView directly).

A solution would be to assign the click event on each item (using OnItemClick) instead of letting the ListView handling it (because it will not work as explained above).

You will have to assign the OnClick event directly on the item (which is a view after all), this is why I assigned the OnClick listener in the getView method of the Adapter, where the item view is being constructed.

So far, instead of having just one listener (OnItemClick), there is as many listeners as items that are visible on the screen, assigned in the getView method of the adapter.

The OnClick listener will be fired if a user clicks anywhere in the item view EXCEPT if where he/she clicks there is a clickable view (like a button ...).

So in this manner the problem is solved, you can assign a click listener to the button and a click listener to the item view.

If the user clicks on the button of the item, the click listener of the button is executed. If the user clicks insides the item view but not on the button, the click listener of the item view is executed because the click listener is set on the item view itself.

One small issue is that, using the approach above, we cannot directly know what is the position of the clicked item view, because if we were using the OnItemClick listener, the call back provides the position in the argument, however in the OnClick listener, you only have the View which was clicked as argument.

In order to solve this small issue, you can store the position of the view as a tag on the view itself using view.setTag ( ... ) and retrieve what you previously stored using view.getTag (). Actually any view can have a tag, which is stored as object, so while retrieving it, cast it back to the required data type.

In this manner, you can know handle click events on ListView items, and know the position of the click item, just like as if you were using a OnItemClick listener.

Hope it helps.

like image 131
Leeeeeeelo Avatar answered Feb 12 '23 18:02

Leeeeeeelo