[Xamarin – Android] Multi Select With Contextual Action Bar (CAB)

On the listview, sometimes we need an action that can select multi data to process it later. We can do it with CAB that you can see here http://developer.android.com/design/patterns/selection.html. This post will show you how to implement it in xamarin android.

Make new project on xamarin, make an activity with listview in the view. Make a view for mainactivity in main.xml and insert this code :

<?xml version=1.0” encoding=utf8?>
   <LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
      android:orientation=vertical
      android:layout_width=fill_parent
      android:layout_height=fill_parent>
      <ListView
         android:id=@+id/mylistview
         android:layout_width=wrap_content
         android:layout_height=wrap_content/>
   </LinearLayout>

In that view we define a listview for show the list data. Before we make CAB, we need to make an application that can show list data in listview so custom your own mainactivity like this :

   public class MainActivity : Activity
  {
      ListView myListView;//define listview
      MyAdapter myAdapter;//definemyadapter(wewillmakethislater)
 
      protected override void OnCreate(Bundle bundle)
      {
        base.OnCreate(bundle);
 
        SetContentView(Resource.Layout.Main);//callmain.xmlforthe view
        myAdapter=new MyAdapter(this);//definemyadapter constructor
        myListView=FindViewById<ListView>(Resource.Id.mylistview);//definelistviewwithlistviewinthe xml
        myListView.Adapter=myAdapter;//setlistviewadapterwith myadapter
      }

You can see that, we have a MyAdapter class that use to make a data list in our listview. Make new class on your application an set the name with MyAdapter and insert this code :

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using Android.App;
 using Android.Content;
 using Android.OS;
 using Android.Runtime;
 using Android.Views;
 using Android.Widget;
 
 using Android.Util;
 
 namespace yournamespace
 {
 class MyAdapter : BaseAdapter
 {
     private LayoutInflater mInflater;
     //itwillshowthe data
     private String[] my_data=new String[]{"This","Is","Sample","Multi","Select"}; //itwillusetoCAB(definethedatathathavebeenselected)
     private SparseBooleanArray mSelectedItemsIds;
     private Contextcontext;
 
     public MyAdapter(Contextcontext){
       mInflater=LayoutInflater.From(context);
       mSelectedItemsIds=new SparseBooleanArray();
       this.context=context;
     }
 
     public override int Count{
        get{return my_data.Length;}
     }
 
     public override Java.Lang.Object GetItem(int position){
        return position;
     }
 
     public override long GetItemId(int position){
        return position;
     }
 
     public override View GetView(int position,View convertView,ViewGroup parent){
         ViewHolder holder=null;
         if(convertView==null || holder==null){
           convertView=mInflater.Inflate(Resource.Layout.my_list,null);
            holder=new ViewHolder();
           //setholderlabelwithlabellistidinthe view
            holder.my_label=convertView.FindViewById<TextView>(Resource.Id.labellist);
            convertView.Tag=(holder);
         }else{
             holder=(ViewHolder)convertView.Tag;
         }
 
         holder.my_label.TextSize=30;//set textSize
         holder.my_label.Text=my_data[position];//setdata label
 
         return convertView;
     }
 
     public class ViewHolder: Java.Lang.Object{
        public TextView my_label;
     }
   }
 }

Dont forget to make a view for each of list data in the my_list.xml in your layout directory :

 <?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/labellist"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"/>

Try to run your code, you will she application like this :Screenshot_2014-07-03-14-09-18
Okey, now we will custom our application to make a CAB. In MyAdapter class, custom the “GetView” function like this :

   public override View GetView(int position,View convertView,ViewGroup parent){
      ViewHolder holder=null;
      if(convertView==null || holder==null){
          convertView=mInflater.Inflate(Resource.Layout.my_list,null);
          holder=new ViewHolder();
          //setholderlabelwithlabellistidinthe view
          holder.my_label=convertView.FindViewById<TextView>(Resource.Id.labellist);
          convertView.Tag=(holder);
       }else{
           holder=(ViewHolder)convertView.Tag;
       }
 
       holder.my_label.TextSize=30;//set textSize
       holder.my_label.Text=my_data[position];//setdata label
 
       //thiswillcheckifthere'sitemthathavebeen selected
       //ifthere'sanitemthatselect,itwillchangetextcolorwith grey
       if(mSelectedItemsIds.Size()>0){
         holder.my_label.SetTextColor(this.mInflater.Context.Resources.GetColor(Resource.Color.grey));
       }
 
       //checkifcurrentitemhavebeen checked
      //ifyes,changetextcolorwith green
       if(mSelectedItemsIds.Get(position)){
           holder.my_label.SetTextColor(this.mInflater.Context.Resources.GetColor(Resource.Color.green));
        }
 
       return convertView;
    }

Find the dirrerences with last code😀 . After change that code, add some function in the MyAdapter class like this :

   public void toggleSelection(int position){
       selectView(position, !mSelectedItemsIds.Get(position));
   }
 
    public void removeSelection(){
        mSelectedItemsIds=new SparseBooleanArray();
        NotifyDataSetChanged();
    }
 
    public void selectView(int position,bool value){
       if(value)
          mSelectedItemsIds.Put(position,value);
       else
          mSelectedItemsIds.Delete(position);
 
       NotifyDataSetChanged();
    }
 
    public int getSelectedCount(){
        return mSelectedItemsIds.Size();
    }
 
    public SparseBooleanArray getSelectedIds(){
      returnmSelectedItemsIds;
    }

Make an xml file in “values” directory with name color.xml, and insert this code there :

 <?xmlversion="1.0"encoding="utf-8"?>
   <resources>
     <colorname="green">#00aa08</color>
     <colorname="grey">#666666</color>
   </resources>
 

Go to your MainActivity and custom your onCreate like this :

   protected override void OnCreate(Bundle bundle)
  {
      base.OnCreate(bundle);
 
      SetContentView(Resource.Layout.Main);//callmain.xmlforthe view
      myAdapter=new MyAdapter(this);//definemyadapter constructor
      myListView=FindViewById<ListView>(Resource.Id.mylistview);//definelistviewwithlistviewinthe xml
      myListView.Adapter=myAdapter;//setlistviewadapterwith myadapter
 
      this.myListView.ItemLongClick+=(sender,e)=>{
        //whenyoudolongclickontheitem,itwillrunthis action
        //wewillmakeit later
        OnListItemSelect(e.Position);
      };
 
      this.myListView.ChoiceMode=ChoiceMode.Multiple;
 }

Stay on you mainActivity, add this code there :

       private ActionMode mActionMode;
 
           private void OnListItemSelect(int position){
               myAdapter.toggleSelection(position);
               bool hasCheckedItems=myAdapter.getSelectedCount()>0;
 
               if(hasCheckedItems && mActionMode==null)
                   mActionMode=StartActionMode(new ActionModeCallback(this));
               elseif(!hasCheckedItems&&mActionMode !=null)
                  mActionMode.Finish();
 
               if(mActionMode !=null)
                   mActionMode.Title=(myAdapter.getSelectedCount().ToString()+"selected");
               }
 
      private class ActionModeCallback : Java.Lang.Object,ActionMode.ICallback
     {
         MainActivity parent;
 
          public ActionModeCallback(MainActivity parent)
         {
           this.parent=parent;
         }
 
         public bool OnCreateActionMode(ActionMode mode,IMenu menu){
            //wewillcallcab_menu.xmlforsetthe menu
            //wewillcreatecab_menu.xml later
            mode.MenuInflater.Inflate(Resource.Layout.cab_menu,menu);
            return true;
        }
 
         public bool OnPrepareActionMode(ActionMode mode,IMenu menu){
            returnfalse;
         }
 
         public bool OnActionItemClicked(ActionMode mode,IMenuItem item){
            switch(item.ItemId){
            //ifuserclickmenu print_me
            case Resource.Id.print_me:
            //createanalert dialog
            AlertDialog.Builder builder=new AlertDialog.Builder(parent);
            string msg="Are you sure you want to print items?";
            builder.SetMessage(msg)
              .SetCancelable(false)
              .SetPositiveButton("Yes",(or,er)=>{
 
                 SparseBooleanArray selected=parent.myAdapter.getSelectedIds();
                 List<string> list_item=new List<string>();
                 for(int i=(selected.Size()-1); i>=0; i--){
                    //checkisvaluecheckedby user
                    if(selected.ValueAt(i)){
                       int selectedItem=(int)parent.myAdapter.GetItem(selected.KeyAt(i));
                       list_item.Add(selectedItem.ToString());
                    }
                }
                //print message
                Toast.MakeText(parent,"YouSelect"+parent.myAdapter.getSelectedCount()+"Item:["+string.Join(",",list_item)+"]",ToastLength.Long).Show();
                mode.Finish();

            })
            .SetNegativeButton("No",(or,er)=>{
                ((Dialog)or).Cancel();
            });

            AlertDialogalert=builder.Create();
            alert.Show();
 
            return true;
          default:
             return false;
        }
     }
 
     public void OnDestroyActionMode(ActionMode mode){
       parent.myAdapter.removeSelection();
       parent.mActionMode=null;
     }
 }
 

Last, create a xml file in layout directory with name cab_menu.xml and insert this code :

   <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/print_me"
            android:showAsAction="always"
            android:title="PrintMe"
            android:visible="true"></item>
   </menu>
 

Okey, try to run our apps now. You will see this code :Untitled

Finish… hope it help..

Happy coding…😀

 

8 Responses to [Xamarin – Android] Multi Select With Contextual Action Bar (CAB)

  1. wolfram says:

    Thanks for this tuturial. I have an error on this line:” builder.SetMessage(msg).SetCancelable(false).SetPositiveButton(“Yes”,(or,er)=>{
    SparseBooleanArray selected = parent.myAdapter.getSelectedIds();

    “(or,er)=>{” – cannot convert lambda expression to type Android.Content.IDialogInterfaceOnClickListener because it is not delegate type.

    Could you help me?

  2. Alireza says:

    How to Implement this code on mvvmcross ,may you help me?

  3. Thank you very much for this article. Could you post the entire source code throw a zip file?
    unfortunately the code snippets that you post are difficult to understand because there are not spaces.

  4. Thank you very much for this tutorial. But I have some problems, could you post a zip file with the source code? Please.
    Some lines of code are difficult to understand because the “space” are missed between words.

  5. Hi, im sorry for late post. I dont know why the code miss the space, but i have been try to fix my post. You should be can fix the space by see the color of code.
    Btw, i cant find my code to send it to you, sorry.

  6. manali says:

    can anyone help me from this how can i change backgorund color of that listview instead of textview colour, mylistview on multiple selection??

  7. manali says:

    please help me in this section

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: