10 Ocak 2018 Çarşamba

Android - How to properly highlight selected item on recyclerview ? Checkbox lost checked value when scrolling in recyclerView, listView. How to solve it?

Recently, i have faced the problem of losing the checked value when scrolling in recyclerView. I searched on the web and didn't find an exact solution. Solved it after some time. However, i faced the similar problem when i wanted to highlight the selected rows.  After some search on the web, i saw that there are lots of people suffering from this problem however the solution is not available. Thus i wanted to share my solution...

I create a project using my own project codes with copy past method, thus the solution may involve some unnecessary parts.

MainActivity.java :

package com.example.oiyio.test_recyclerview_highlight;

  import android.support.design.widget.TabLayout;
  import android.support.v4.app.Fragment;
  import android.support.v4.app.FragmentManager;
  import android.support.v4.app.FragmentPagerAdapter;
  import android.support.v4.view.ViewPager;
  import android.support.v7.app.ActionBar;
  import android.support.v7.app.AppCompatActivity;
  import android.os.Bundle;
  import android.support.v7.widget.Toolbar;
  import android.view.MenuItem;

  import java.util.ArrayList;
  import java.util.List;

public class MainActivity extends AppCompatActivity {
  public Toolbar toolbar;

  private TabLayout tabLayout;
  private ViewPager viewPager;
  MyFragment myFragment;
  private ActionBar ab;

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

    /* Toolbar and Tabs added */    toolbar = (Toolbar) findViewById(R.id.toolbar);

    setSupportActionBar(toolbar);

    ab = getSupportActionBar();

    ab.setHomeAsUpIndicator(R.drawable.ic_menu);
    ab.setDisplayHomeAsUpEnabled(true);



    viewPager = (ViewPager) findViewById(R.id.viewpager);
    setupViewPager(viewPager);

    tabLayout = (TabLayout) findViewById(R.id.tabs);

    // tab ve tab icerigini bagladik.    tabLayout.setupWithViewPager(viewPager);
      /*end*/  }

  @Override  public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
      case android.R.id.home:
        if(MyFragment.is_in_action_mode)
        {
          onBackPressed(); // back button        }
        else        {
        }
        return true;
    }
    return super.onOptionsItemSelected(item);
  }
  @Override  public void onBackPressed() {
    if(myFragment.is_in_action_mode)
    {
      myFragment.clearActionM();
      myFragment.adapter.notifyDataSetChanged();  // bu gerekli mi gercekten ???    }
    else {
      super.onBackPressed();
    }
  }

  @Override  protected void onResume() {
    super.onPause();
    RV_Adapter m = new RV_Adapter();
  }

  // tabLayout'a 3 tane tab yani 3 tane fragment ekler:  private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    myFragment = new MyFragment();
    adapter.addFrag(myFragment, "My Tab");
    viewPager.setAdapter(adapter);
  }

  class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
      super(manager);
    }

    @Override    public Fragment getItem(int position) {
      return mFragmentList.get(position);
    }

    @Override    public int getCount() {
      return mFragmentList.size();
    }

    public void addFrag(Fragment fragment, String title) {
      mFragmentList.add(fragment);
      mFragmentTitleList.add(title);
    }

    @Override    public CharSequence getPageTitle(int position) {
      return mFragmentTitleList.get(position);
    }
  }
}


MyFragment.java 

package com.example.oiyio.test_recyclerview_highlight;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.RelativeLayout;

import java.util.ArrayList;
import android.support.v7.widget.DividerItemDecoration;
import jp.wasabeef.recyclerview.animators.LandingAnimator;

public class MyFragment extends Fragment implements View.OnLongClickListener {
    public static boolean is_in_action_mode = false;
    View mainLayout;
    ArrayList<String> selectionList = new ArrayList<String>();
    ArrayList<RelativeLayout> relativeLayoutList = new ArrayList<RelativeLayout>();
    Toolbar toolbar ;

    private RecyclerView recyclerView;
    public RV_Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private DividerItemDecoration dividerItemDecoration;
    ArrayList<String> foodList=new ArrayList<String>();

    public MyFragment() {
    }

    @Override    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
      ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);

      for(int i = 0;i<30;i++)
        foodList.add("Item" + i);
    }

    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mainLayout = inflater.inflate(R.layout.fragment, container, false);
      return mainLayout;
    }

    @Override    public void onPause() {
      super.onPause();
      is_in_action_mode = false;
      removeRelativeLayoutList();
    }

    @Override    public void onResume() {
      super.onResume();
      updateList();
      adapter.notifyDataSetChanged();
    }

    public void updateList(){
      adapter.updateList(foodList);
    }

    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
      super.onViewCreated(view, savedInstanceState);
      recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
      adapter = new RV_Adapter(getActivity(), this, foodList);
      recyclerView.setItemAnimator(new LandingAnimator());

      layoutManager = new LinearLayoutManager(this.getContext());
      recyclerView.setLayoutManager(layoutManager);
      dividerItemDecoration = new DividerItemDecoration(getActivity(), LinearLayoutManager.VERTICAL);
      recyclerView.setAdapter(adapter);
      recyclerView.addItemDecoration(dividerItemDecoration);
    }

    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
    }

    @Override    public boolean onLongClick(View v)
    {
      is_in_action_mode = true;
      adapter.notifyDataSetChanged();
      ((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
      ((MainActivity)getActivity()).setSupportActionBar(toolbar);
      ((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);

      return true;
    }

    public void prepareselection(View view, int position, RelativeLayout relativeLayout)
    {
      relativeLayoutList.add(relativeLayout);

      if(((CheckBox)view).isChecked())
      {
        selectionList.add(foodList.get(position));
      }
      else {
        selectionList.remove(foodList.get(position));
      }
    }

    private void removeRelativeLayoutList() {
      for(RelativeLayout rel : relativeLayoutList)
        rel.setBackgroundResource(R.color.food_unselected);
    }

  public void clearActionM()
  {
    is_in_action_mode = false;
    toolbar.getMenu().clear();

    //While returning from action mode(selection mode) to non-action mode, back button on the toolbar replaced by ic_menu button.    ((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    ((MainActivity)getActivity()).getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);

    adapter.resetCheckBoxState();
    removeRelativeLayoutList();
  }
}

RV_Adapter.java

package com.example.oiyio.test_recyclerview_highlight;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;

/** * Created by IamDeveloper on 8/16/2016. */public class RV_Adapter extends RecyclerView.Adapter<RV_Adapter.ViewHolder> {
    public ArrayList<String> list;
    boolean[] checkBoxState;
    MainActivity mainActivity;
    MyFragment myFragment;
    View firstview;

    private Context context;

    FrameLayout framelayout;

    public RV_Adapter() {

  }

    public RV_Adapter(Context context, MyFragment m, ArrayList<String> list ) {
      this.list = list;
      myFragment = m;
      this.context = context;
      mainActivity = (MainActivity) context;
      checkBoxState = new boolean[list.size()];
      // relativeLayoutState = new boolean[list.size()];    }

    public class ViewHolder extends RecyclerView.ViewHolder  {
        public TextView textView;
        public CheckBox checkBox;
        RelativeLayout relativeLayout;
        MainActivity mainActivity;
        MyFragment myFragment;
        public ViewHolder(View v,MainActivity mainActivity,MyFragment m) {
            super(v);
            textView = (TextView) v.findViewById(R.id.tv_foodname);
            /**/            checkBox= (CheckBox) v.findViewById(R.id.checkBox);
            relativeLayout = (RelativeLayout)v.findViewById(R.id.relativelayout);
            this.mainActivity = mainActivity;
            this.myFragment = m;
            framelayout = (FrameLayout) v.findViewById(R.id.framelayout);
            framelayout.setOnLongClickListener(m);
        }

    }

    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        firstview = inflater.inflate(R.layout.row, parent, false);
        return new ViewHolder(firstview,mainActivity, myFragment);
    }

    @Override    public void onBindViewHolder( final ViewHolder holder,  final int position) {

        holder.textView.setText(list.get(position));

        holder.itemView.setOnClickListener(new View.OnClickListener() {
          @Override          public void onClick(View v) {

          }
        });

        // When action mode is active, checkboxes are displayed on each row, handle views(move icons) on each row are disappered.        if(!myFragment.is_in_action_mode)
        {

          holder.checkBox.setVisibility(View.GONE);
        }
        else        {
          holder.checkBox.setVisibility(View.VISIBLE);
          holder.checkBox.setChecked(false);
        }

          holder.checkBox.setTag(position);

          holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
            @Override            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
              if(compoundButton.isPressed()) // ekrandan kaybolan checkbox'lar otomatik olarak state degistiriyordu ve bu listener method cagiriliyordu, bunu onlemek icin isPressed() method'u ile kullanici mi basmis diye kontrol ediyorum.              {
                int getPosition = (Integer) compoundButton.getTag();  // Here we get the position that we have set for the checkbox using setTag.                checkBoxState[getPosition] = compoundButton.isChecked(); // Set the value of checkbox to maintain its state.                //relativeLayoutState[getPosition] = compoundButton.isChecked();
              if(checkBoxState[getPosition] && getPosition == position )
                holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view  **/              else                holder.relativeLayout.setBackgroundResource(R.color.food_unselected); /** Change background color of the selected items in list view  **/                myFragment.prepareselection(compoundButton, getPosition, holder.relativeLayout);

              }
            }
          });
          holder.checkBox.setChecked(checkBoxState[position]);

          if(checkBoxState[position]  )
            holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view  **/          else            holder.relativeLayout.setBackgroundResource(R.color.food_unselected);
    }



    @Override    public int getItemCount() {
        return list.size();
    }

    public void updateList(ArrayList<String> newList){
      this.list = newList;
      checkBoxState = new boolean[list.size()+1];
    }

  public void resetCheckBoxState(){
    checkBoxState = null;
    checkBoxState = new boolean[list.size()];
  }

}

activity_main.xml
<?xml version="1.0"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="match_parent"
                                                 android:fitsSystemWindows="true">
 <android.support.design.widget.AppBarLayout android:layout_width="match_parent"
                                             android:layout_height="wrap_content"
                                             android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
  <android.support.v7.widget.Toolbar android:id="@+id/toolbar"
                                     android:layout_width="match_parent"
                                     android:layout_height="?attr/actionBarSize"
                                     android:background="?attr/colorPrimary"
                                     app:layout_scrollFlags="scroll|enterAlways"
                                     app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
   <RelativeLayout android:layout_width="match_parent"
                   android:layout_height="wrap_content">
    <TextView android:id="@+id/tv_title"
              android:layout_toRightOf="@+id/iv_icon"
              android:layout_centerVertical="true"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:background="?attr/selectableItemBackground"
              android:layout_marginLeft="10dp"
              android:text="CheckBox and Highlight"
              android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"/>
    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/cnt_text"
              android:text="0 item selected"
              android:textColor="#fff"
              android:textSize="20dp"
              android:textStyle="italic|bold"
              android:visibility="gone"/>
   </RelativeLayout>
  </android.support.v7.widget.Toolbar>
  <android.support.design.widget.TabLayout android:id="@+id/tabs"
                                           android:layout_width="match_parent"
                                           android:layout_height="wrap_content"
                                           app:tabMode="scrollable"/>
 </android.support.design.widget.AppBarLayout>
 <!-- Tab'in altindaki alandir. FrameLayout'un arkasindaki alandir. -->
 <android.support.v4.view.ViewPager android:id="@+id/viewpager"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    app:layout_behavior="@string/appbar_scrolling_view_behavior"
                                    android:background="@color/food_unselected"/>
</android.support.design.widget.CoordinatorLayout>


row.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/framelayout"
             android:layout_width="match_parent"
             android:layout_height="?listPreferredItemHeight"
             android:clickable="true"
             android:focusable="true"
             android:foreground="?selectableItemBackground"      >
  <!--  android:background="?android:attr/activatedBackgroundIndicator"  -->  <!-- android:background="@color/food_unselected" -->  
  <RelativeLayout    android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/relativelayout">

    <CheckBox      android:layout_width="wrap_content"
                   android:layout_height="match_parent"
                   android:id="@+id/checkBox"
                   android:layout_marginLeft="5dp"
                   android:visibility="gone"      />

    <TextView      android:id="@+id/tv_foodname"
                   android:layout_toRightOf="@id/checkBox"
                   android:layout_width="wrap_content"
                   android:scaleType="center"
                   android:layout_height="match_parent"
                   android:layout_gravity="center_vertical"
                   android:layout_marginLeft="5dp"
                   android:gravity="center_vertical"
                   android:textAppearance="?android:attr/textAppearanceMedium" />

  </RelativeLayout>
</FrameLayout>



fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="wrap_content"> </android.support.v7.widget.RecyclerView> </LinearLayout>



Download link : 

https://www.dropbox.com/s/ssm58w62gw32i29/recyclerView_checkbox_highlight.zip?dl=0

Hiç yorum yok:

Yorum Gönder