Search code examples
androidxamarinxamarin.androidmvvmcross

MvxRecycleView selected item background


How can I set selected item background in MvxRecycleView?

I want to change background of selected item while another.

selector_category_item.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item  android:state_pressed="true"  android:state_enabled="true"  >
        <shape android:shape="rectangle">
            <solid android:color="@color/colorPrimary"/>
        </shape>
            </item>

    <item android:state_checked="false" android:state_enabled="true"  >
        <shape android:shape="rectangle">
            <solid android:color="@color/grayBackground"/>
        </shape>
    </item>
</selector>

My MvxRecycleView

<MvxRecyclerView
            android:overScrollMode="never"
            android:scrollbars="vertical"
            android:background="#e2e2e2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            local:MvxItemTemplate="@layout/category_item"
            local:MvxBind="ItemsSource Categories; ItemClick SelectCategoryCommand; SelectedItem SelectedCategory"
            android:id="@+id/categoryRecyclerView" />

And category_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:clickable="true"
    android:background="@drawable/selector_category_item"
    android:layout_marginBottom="1dp"
    android:orientation="vertical">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ffimageloading.cross.MvxCachedImageView
            android:id="@+id/categoryImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            local:MvxBind="DrawableName CategoryImage" />
        <ImageView
            android:id="@+id/favIcon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentEnd="true"
            android:src="@drawable/no_fav_icon" />
    </RelativeLayout>
    <TextView
        android:clickable="true"
    android:focusableInTouchMode="true"
    android:focusable="true"
        android:layout_marginTop="8dp"
        android:id="@+id/categoryText"
        style="@style/TextStyleBlack"
        android:fontFamily="@font/roboto_regular"
        android:letterSpacing="-0.04"
        android:lineSpacingExtra="0sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        local:MvxBind="Text Name"
        android:textSize="14sp" />
</LinearLayout>

I need change selected item background to other while item is selected. How can I sort it out?


Solution

  • You can make a custom MvxRecyclerView adapter to handle selection:

    public class MyRecyclerAdapter : MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerAdapter
    {
        public MyRecyclerAdapter(IMvxAndroidBindingContext bindingContext) : base(bindingContext)
        {
        }
    
        public MyRecyclerAdapter(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
        }
    
        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            base.OnBindViewHolder(holder, position);
            holder.ItemView.Selected = _selectedPosition == position;
            holder.ItemView.Click += (s, e) => SelectIndex(holder.AdapterPosition);
        }
    
        private void SelectIndex(int index)
        {
            NotifyItemChanged(_selectedPosition);
            _selectedPosition = index;
            NotifyItemChanged(_selectedPosition);
        }
    
        private int _selectedPosition = RecyclerView.NoPosition;
    }
    

    Then you want to set the MvxRecyclerView.Adapter property somewhere in your view. The ideal place is usually OnCreate for an activity, or OnCreateView for a fragment:

    recyclerView.Adapter = new MyRecyclerAdapter((IMvxAndroidBindingContext)BindingContext);

    At this point you have a RecyclerView which sets the item you click on as selected. Now you can use a ColorStateList to change the color depending on the selection state. Add the file to Resources\drawable\selector_category_item.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item 
        android:drawable="@color/colorAccent"
        android:state_pressed="true" />
      <item 
        android:drawable="@color/colorPrimary"
        android:state_selected="true" />
    </selector>
    

    Finally set the background of the category_item.xml LinearLayout to:

    android:background="@drawable/selector_category_item"
    

    It's worth pointing out you can also use a different ColorStateList to change the android:textColor as desired based on the selection state as well. You just need to put those ColorStateList XML files in the Resources\color folder instead of Resources\drawable.

    I posted a working sample on GitHub.