How do I get ItemClick of a ListView to get called? Not sure what have wrong.

TonyScamurraTonyScamurra USMember
edited January 2013 in Xamarin.Android

I have the following code:

protected override void OnCreate (Bundle bundle)
{
    progress = ProgressDialog.Show(this, "", "Loading...");
    progress.SetProgressStyle(ProgressDialogStyle.Spinner);

    base.OnCreate (bundle);

    //Set the Activity's view to our list layout        
    SetContentView(Resource.Layout.LawsAndRegsList);

    new Thread(new ThreadStart(() => {
        //Create our adapter
        listAdapter = new LawsAndRegsListAdapter(this);
        this.RunOnUiThread ( () => {
            //Find the listview reference
            listView = FindViewById<ListView>(Resource.Id.listView);

            //Hook up our adapter to our ListView
            listView.Adapter = listAdapter;

            //Wire up the click event
            //listView.ItemClick += new EventHandler<ListView.ItemClickEventArgs>(listView_ItemClick);
            listView.ItemClick += listView_ItemClick;

            listAdapter.NotifyDataSetChanged(); 

            progress.Dismiss();
        });
    })).Start();
}

void listView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
    //Get our item from the list adapter
    var item = this.listAdapter.GetItemAtPosition(e.Position);

    //Make a toast with the item name just to show it was clicked
    Toast.MakeText(this, item.Name + " Clicked!", ToastLength.Short).Show();
}

Can anyone tell me why the ItemClick would not get called?

It looks like what I have read and examples I have seen so what am I doing wrong?

Thanks for the help.

Best Answer

Answers

  • CheesebaronCheesebaron DKInsider, University mod

    Have you tried doing it without the background thread?

  • TonyScamurraTonyScamurra USMember

    Yes I have. At this point I have tried so many things I am lost. Anyway, I think it may have to do with the layout... does that make sense? If I use some code from a sample then the event does get called, but if I modify it a bit and change the code so it uses my layout it does not get called.

  • CheesebaronCheesebaron DKInsider, University mod

    Can you please show us the layout? :)

  • TonyScamurraTonyScamurra USMember
    edited January 2013

    Here are the two layouts I have:

    LawsAndRegsList:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/widget28"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical">
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/topLevelMenuBackground"
            android:orientation="horizontal">
            <Button
                android:id="@+id/btnAddExpense"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:text="@string/ButtonHome"
                android:layout_centerVertical="true" />
            <TextView
                android:id="@+id/lblExpenseCancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="15dp"
                android:text="@string/LawsAndRegs"
                android:textColor="#ffffffff"
                android:textSize="20sp"
                android:layout_centerVertical="true" />
        </RelativeLayout>
        <ListView
            android:id="@+id/listView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    LawsAndRegsListItem:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/widget28"
        android:layout_width="fill_parent"
        android:background="@drawable/topLevelMenuCellBackground"
        android:layout_height="40px">
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <ImageView
                android:id="@+id/imageItem"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_centerVertical="true"
                android:layout_gravity="center_vertical" />
            <TextView
                android:id="@+id/textTop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:textColor="#111479"
                android:text="hello"
                android:layout_toRightOf="@+id/imageItem"
                android:textStyle="bold"
                android:layout_marginLeft="10dp" />
            <ImageButton
                android:src="@drawable/OrangeAccessoryButton"
                android:layout_width="wrap_content"
                android:layout_height="25dp"
                android:layout_alignParentRight="true"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="15dp"
                android:layout_centerVertical="true"
                android:id="@+id/imageButton1"
                android:background="@android:color/transparent" />
        </RelativeLayout>
    </LinearLayout>
    

    UPDATE:

    I have replaced this code:

    var view = (convertView ?? context.LayoutInflater.Inflate(Resource.Layout.LawsAndRegsListItem, parent, false)) as LinearLayout;
    
    //Find references to each subview in the list item's view
    ImageView imgView = (ImageView)view.FindViewById(Resource.Id.imageItem);
    TextView textTop = (TextView)view.FindViewById(Resource.Id.textTop);
    
    var bm = BitmapFactory.DecodeStream(new Java.Net.URL("http://www.massdental.org/" + item.Image).OpenStream());
    imgView.SetImageBitmap(bm);
    
    //Assign this item's values to the various subviews
    textTop.SetText(item.Name, TextView.BufferType.Normal);
    

    With this and the event does get called:

    var view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem2, null);
    view.FindViewById<TextView> (Android.Resource.Id.Text1).Text = item.Name;
    view.FindViewById<TextView> (Android.Resource.Id.Text2).Text = item.Description;
    

    I think that would bring me to a problem with my layout, right? Or, maybe I need to add to the code, maybe a listener or something?

    Thanks for the help!!

  • TonyScamurraTonyScamurra USMember
    edited January 2013

    If I change my GetView to this, hen OnItemListGetsCalled.

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
    //Get our object for this position
    var item = items[position];

    var view = context.LayoutInflater.Inflate(Android.Resource.Layout.ActivityListItem, null);
    view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = item.Name;
    //view.FindViewById<TextView>(Android.Resource.Id.Text2).Text = item.SubHeading;
    var bm = BitmapFactory.DecodeStream(
        new Java.Net.URL("http://www.massdental.org/" + item.Image).OpenStream());
    view.FindViewById<ImageView>(Android.Resource.Id.Icon).SetImageBitmap(bm);
    

    // var view = context.LayoutInflater.Inflate(Resource.Layout.LawsAndRegsListItem, null);

    //Find references to each subview in the list item's view
    

    // ImageView imgView = (ImageView)view.FindViewById(Resource.Id.imageItem);
    // TextView textTop = (TextView)view.FindViewById(Resource.Id.textTop);

    //Assign this item's values to the various subviews
    

    // var bm = BitmapFactory.DecodeStream(
    // new Java.Net.URL("http://www.somesite.com/" + item.Image).OpenStream());
    // imgView.SetImageBitmap(bm);

    // textTop.SetText(item.Name, TextView.BufferType.Normal);

    //Finally return the view
    return view;
    

    }

    So how do I get it to work with my custom layout? What am I missing?

  • TonyScamurraTonyScamurra USMember

    OMG!!!! Yes, that worked. I understand your explanation!! This has taken me two days, you are awesome thanks for the help!!! One last small thing i noticed. If I click the accessory buttons from the bottom up, 3, 2, 1, and then 0, I get this output:

    ImageButton 3 clicked
    ImageButton 2 clicked
    ImageButton 1 clicked
    ImageButton 0 clicked
    ImageButton 1 clicked
    ImageButton 2 clicked
    ImageButton 3 clicked
    ImageButton 0 clicked
    

    It seems that the click on 3 is ok, 2 is ok, 1 is ok, but 0 causes 0, 1, 2, 3, and then 0 to be displayed. Lead me to believe that the evnt is fired 5 times for item 0.

    Makes sense?

    Thanks again!!

  • aaronmixaaronmix USMember, Beta

    You should add delegate to ImageButton's click event when the view is first created. Otherwise, it will be subscribed every time GetView is called.

    var view = convertView
    if(view == null){
        view = context.LayoutInflater.Inflate(Android.Resource.Layout.ActivityListItem, null);
        view.FindViewById<ImageButton>(Resource.Id.imageButton1).Click += (sender, args) => Console.WriteLine("ImageButton {0} clicked", position);
    }
    
  • aaronmixaaronmix USMember, Beta

    Back to the click question. I suggested that android:descendantFocusability="blocksDescendants" could be put into item's root ViewGroup's attribute, so it will prevent its children from getting focused. But, somehow this solution didn't solve the question. Any ideas?

    See the post on stackoverflow: http://stackoverflow.com/questions/14443364/unable-to-get-listview-itemclick-to-be-called-in-monodroid

  • If you have an ImageButton in your customer list item view group at all anywhere, the "OnListItemClick" event will not fire as the ImageButton steals the click even if the focus and click are both false. Either you have to add a click handler to the ImageButton to manually handle, or you can add android:descendantFocusability="blocksDescendants" to your root list item view group (e.g. LinearLayout) and that will prevent any ImageButtons from stealing the focus/click.

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/contactItemLinearLayout"
        android:descendantFocusability="blocksDescendants">
    
  • If you have an ImageButton in your customer list item view group at all anywhere, the "OnListItemClick" event will not fire as the ImageButton steals the click even if the focus and click are both false. Either you have to add a click handler to the ImageButton to manually handle, or you can add android:descendantFocusability="blocksDescendants" to your root list item view group (e.g. LinearLayout) and that will prevent any ImageButtons from stealing the focus/click.

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/contactItemLinearLayout"
        android:descendantFocusability="blocksDescendants">
    
  • rohitjenarohitjena USMember

    hi, I am New to xamarin . I are developing an Applciation where i need to display items in a ListView. I am able to display the Item in List View. I have an Image , TextView and ImageButton(Fav Button). Now i am not able to fire the ItemsClick event for the ListView. How can select the Image button on click of each row in ListView.
    I had tried the above solutions but didnt work.

  • carleslscarlesls ESMember

    You should add delegate to ImageButton's click event when the view is first created. Otherwise, it will be subscribed every time GetView is called.

    var view = convertView
    if(view == null){
        view = context.LayoutInflater.Inflate(Android.Resource.Layout.ActivityListItem, null);
        view.FindViewById<ImageButton>(Resource.Id.imageButton1).Click += (sender, args) => Console.WriteLine("ImageButton {0} clicked", position);
    }
    

    or?
    Let me guess what it may happend... the event will be activated in other views from other custom rows.

  • KerryGrahamKerryGraham USUniversity ✭✭

    None of the solutions involving focus actually worked for me. The ItemClick handler was still not called when I had a custom adapter that changed the layout and used a button. What did work was passing my ListView into my adapter's constructor and then calling ListView.PerformItemClick from my button Click handler. Easy solution without black magic.

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View view = convertView;
            if (view == null) // no view to re-use, create new
            {
                view = context.LayoutInflater.Inflate(Tools.Resource.Layout.QuestionListItem, null);
                view.FindViewById<Button>(Tools.Resource.Id.listViewButton).Click += (sender, args) =>
                {
                    listView.PerformItemClick(view, position, GetItemId(position));
                };
            }
            view.FindViewById<Button>(Tools.Resource.Id.listViewButton).Text = items[position];
    
            return view;
        }
    
  • Thanks KerryGraham - I had the same problem, and that is the solution that worked for me. It apear that the buttons inside the item are collecting the touch event before the onItemClicked event.

    Do you know by chance if this is the general behavior in Android, or is it different in Xamarin?

Sign In or Register to comment.