Thursday, August 24, 2017

“changing height of recycler view's item view” on click of item view

Leave a Comment

I have a fragment with a search view and a recycler view with which you can select one item at a time. Item height may vary depending on the content being displayed. When a recycler views item is clicked, I am changing the background color of that item, and then storing the selected item to a variable for later use. However, when the item is being selected, height of it is also changing dramatically. Its like item's detail is being collapsed or expended unintentionally.

I am not very sure, but I think it has something to do with the reuse of cell. I am unable to figure out the exact issue as I just started working on android.

Here is the link to the video showing the problem, in case needed.

How can I fix this? Please point me to the right direction.

My adapter class is-

public class CodeListAdapter extends RecyclerView.Adapter<CodeListAdapter.ViewHolder> {      private List<Code> codes;     private Code selectedCode;     private int selectedPosition = -1;      public CodeListAdapter(Code selectedCode) {         this.selectedCode = selectedCode;     }      @Override     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_code, parent, false);         return new ViewHolder(view);     }      @Override     public void onBindViewHolder(ViewHolder holder, int position) {         Code code = codes.get(position);         holder.codeIdentifier.setText(code.getCodeIdentifier());          if (code.getCodeType() == null || code.getCodeType().isEmpty()) {             holder.codeType.setVisibility(View.GONE);         } else {             holder.codeType.setText(code.getCodeType());         }          if (code.getCodeDescription() == null || code.getCodeDescription().isEmpty()) {             holder.codeDescription.setVisibility(View.GONE);         } else {             holder.codeDescription.setText(code.getCodeDescription());         }          if (selectedCode == code) {             holder.itemLayout.setBackgroundResource(R.color.colorEmphasis);         } else {             holder.itemLayout.setBackgroundResource(R.color.colorWhite);         }          final ViewHolder viewHolder = holder;         holder.itemLayout.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View itemView) {                 int currentPosition = viewHolder.getAdapterPosition();                 if (currentPosition != selectedPosition) {                     selectedCode = codes.get(currentPosition);                     notifyItemChanged(selectedPosition);                     selectedPosition = currentPosition;                     notifyItemChanged(selectedPosition);                 }             }         });     }      @Override     public int getItemCount() {         return codes.size();     }      public void setCodes(List<Code> codes) {         this.codes = codes;     }      public Code getCode() {         return selectedCode;     }      static class ViewHolder extends RecyclerView.ViewHolder {         View itemLayout;         TextView codeIdentifier;         TextView codeType;         TextView codeDescription;          ViewHolder(View view) {             super(view);             itemLayout = view.findViewById(R.id.item_layout);             codeIdentifier = (TextView) view.findViewById(R.id.codeIdentifier);             codeType = (TextView) view.findViewById(R.id.codeType);             codeDescription = (TextView) view.findViewById(R.id.codeDescription);         }     } } 

Item's layout file is-

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:background="@color/black75PercentColor"     android:paddingBottom="1dp">      <RelativeLayout         android:id="@+id/item_layout"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:background="@color/white"         android:paddingBottom="6dp"         android:paddingEnd="12dp"         android:paddingStart="12dp"         android:paddingTop="6dp">          <TextView             android:id="@+id/codeIdentifier"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:layout_alignParentStart="true"             android:layout_alignParentTop="true" />          <TextView             android:id="@+id/codeType"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@+id/codeIdentifier" />          <TextView             android:id="@+id/codeDescription"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@id/codeType" />     </RelativeLayout> </FrameLayout> 

Layout file is-

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:orientation="vertical">      <SearchView         android:id="@+id/searchView"         android:layout_width="match_parent"         android:layout_height="50dp"         android:queryHint="@string/key_search_code" />      <RelativeLayout         android:layout_width="match_parent"         android:layout_height="40dp"         android:background="@color/colorPrimary"         android:paddingEnd="12dp"         android:paddingStart="12dp">          <TextView             android:id="@+id/headerTextView"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:gravity="center_vertical"             android:text="Codes"             android:textColor="@color/white"             android:textSize="20sp" />      </RelativeLayout>      <mdbilling.ca.mdbilling_android.Customs.ExtendedRecyclerView         android:id="@+id/diagnosticCodeRecyclerView"         android:layout_width="match_parent"         android:layout_height="match_parent" />      <RelativeLayout         android:id="@android:id/empty"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:layout_gravity="center"         android:gravity="center"         android:paddingEnd="12dp"         android:paddingStart="12dp">          <TextView             android:id="@+id/messageHeader"             style="?android:attr/textAppearanceLarge"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:textAlignment="center" />          <TextView             android:id="@+id/messageBody"             style="?android:attr/textAppearanceMedium"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@+id/messageHeader"             android:layout_marginTop="6dp"             android:textAlignment="center" />     </RelativeLayout>  </LinearLayout> 

Customs.ExtendedRecyclerView here is nothing but an extension (from this gist) of recycler view which have the capability of displaying @android:id/empty view, whenever dataset in adapter is empty.

Did I do anything wrong or is it the way it is?

Thanks in advance!

3 Answers

Answers 1

I've tested your code. I will share the video recorded and the source code to you. May It can help you find the issue.

MainActivity:

package info.androidhive.recyclerview;  import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Toast;  import java.util.ArrayList; import java.util.List;  public class MainActivity extends AppCompatActivity {     private List<Movie> movieList = new ArrayList<>();     private RecyclerView recyclerView;     private MoviesAdapter mAdapter;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);         setSupportActionBar(toolbar);          recyclerView = (RecyclerView) findViewById(R.id.recycler_view);          mAdapter = new MoviesAdapter(movieList);          recyclerView.setHasFixedSize(true);         RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());         recyclerView.setLayoutManager(mLayoutManager);         recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));         recyclerView.setItemAnimator(new DefaultItemAnimator());         recyclerView.setAdapter(mAdapter);          recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new RecyclerTouchListener.ClickListener() {             @Override             public void onClick(View view, int position) {                 Movie movie = movieList.get(position);                 Toast.makeText(getApplicationContext(), movie.getTitle() + " is selected!", Toast.LENGTH_SHORT).show();             }              @Override             public void onLongClick(View view, int position) {              }         }));          prepareMovieData();     }      private void prepareMovieData() {         Movie movie = new Movie("Mad Max: Fury Road", "Action & Adventure", "2015");         movieList.add(movie);          movie = new Movie("Inside Out", "Animation, Kids & Family", "2015");         movieList.add(movie);          movie = new Movie("Star Wars: Episode VII - The Force Awakens", "Action", "2015");         movieList.add(movie);          movie = new Movie("Shaun the Sheep", "Animation", "2015");         movieList.add(movie);          movie = new Movie("The Martian", "Science Fiction & Fantasy", "2015");         movieList.add(movie);          movie = new Movie("Mission: Impossible Rogue Nation", "Action", "2015");         movieList.add(movie);          movie = new Movie("Up", "Animation", "2009");         movieList.add(movie);          movie = new Movie("Star Trek", "Science Fiction", "2009");         movieList.add(movie);          movie = new Movie("The LEGO Movie", "Animation", "2014");         movieList.add(movie);          movie = new Movie("Iron Man", "Action & Adventure", "2008");         movieList.add(movie);          movie = new Movie("Aliens", "Science Fiction", "1986");         movieList.add(movie);          movie = new Movie("Chicken Run", "Animation", "2000");         movieList.add(movie);          movie = new Movie("Back to the Future", "Science Fiction", "1985");         movieList.add(movie);          movie = new Movie("Raiders of the Lost Ark", "Action & Adventure", "1981");         movieList.add(movie);          movie = new Movie("Goldfinger", "Action & Adventure", "1965");         movieList.add(movie);          movie = new Movie("Guardians of the Galaxy", "Science Fiction & Fantasy", "2014");         movieList.add(movie);          mAdapter.notifyDataSetChanged();     }  } 

The adapter:

package info.androidhive.recyclerview;  import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView;  import java.util.List;  public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MyViewHolder> {      private List<Movie> moviesList;     private Movie selectedMovie;     private int lastSelectedPosition = -1;      public class MyViewHolder extends RecyclerView.ViewHolder {         public TextView title, year, genre, desc;          public MyViewHolder(View view) {             super(view);             title = (TextView) view.findViewById(R.id.title);             genre = (TextView) view.findViewById(R.id.genre);             year = (TextView) view.findViewById(R.id.year);             desc = (TextView) view.findViewById(R.id.desc);         }     }       public MoviesAdapter(List<Movie> moviesList) {         this.moviesList = moviesList;     }      @Override     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View itemView = LayoutInflater.from(parent.getContext())                 .inflate(R.layout.movie_list_row, parent, false);          return new MyViewHolder(itemView);     }      @Override     public void onBindViewHolder(MyViewHolder holder, int position) {         Movie movie = moviesList.get(position);         holder.title.setText(movie.getTitle());         holder.genre.setText(movie.getGenre());         holder.year.setText(movie.getYear());         holder.desc.setText(movie.getGenre() + movie.getGenre() + movie.getGenre() + movie.getGenre() + movie.getGenre() + movie.getGenre() + movie.getGenre());          if (selectedMovie == movie) {             holder.itemView.setBackgroundResource(R.color.colorEmphasis);         } else {             holder.itemView.setBackgroundResource(R.color.colorWhite);         }          final RecyclerView.ViewHolder viewHolder = holder;         holder.itemView.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View itemView) {                 int currentPosition = viewHolder.getAdapterPosition();                 if (currentPosition != lastSelectedPosition) {                     selectedMovie = moviesList.get(currentPosition);                     notifyItemChanged(lastSelectedPosition);                     lastSelectedPosition = currentPosition;                     notifyItemChanged(lastSelectedPosition);                 }             }         });     }      @Override     public int getItemCount() {         return moviesList.size();     } } 

Row layout:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:focusable="true"     android:paddingLeft="16dp"     android:paddingRight="16dp"     android:paddingTop="10dp"     android:paddingBottom="10dp"     android:clickable="true"     android:background="?android:attr/selectableItemBackground"     android:orientation="vertical">      <TextView         android:id="@+id/title"         android:textColor="@color/title"         android:textSize="16dp"         android:textStyle="bold"         android:layout_alignParentTop="true"         android:layout_width="match_parent"         android:layout_height="wrap_content" />      <TextView         android:id="@+id/genre"         android:layout_below="@id/title"         android:layout_width="match_parent"         android:layout_height="wrap_content" />      <TextView         android:id="@+id/year"         android:textColor="@color/year"         android:layout_width="wrap_content"         android:layout_alignParentRight="true"         android:layout_height="wrap_content" />      <TextView         android:id="@+id/desc"         android:textColor="@color/year"         android:layout_width="match_parent"         android:layout_alignTop="@+id/genre"         android:layout_height="wrap_content" />  </RelativeLayout> 

And finally the video:

Video showing the code works just fine

TG.

// UPDATE_1 ***

The complete source code is shared in zip file format here:

source code

Answers 2

If i correctly understand what your problem is, you should set your view's click listener inside the ViewHolder class.

Answers 3

Try this, you don't need to call for int currentPosition = viewHolder.getAdapterPosition(); instead you can use the position from the onBindeViewHolder Method itself, for changing the background you just need to call holder.itemView.setOnCLickListner(); if you want to select deselect the itemRow then just keep a flag for that selected position as selected/ not selected.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment