I struggled with a visual bug in my RecyclerView until I noticed that it's caused by putting my RecyclerView into a ConstraintLayout.
This is what I tried to achieve (RecyclerView with GridLayoutManager inside LinearLayout):
And that was my first attempt (RecyclerView with GridLayoutManager inside ConstraintLayout):
So my question is: Why aren't the RecyclerView items aligend properly when the RecyclerView lives within a ConstraintLayout?
A look with the Layout Inspector yields that the RecyclerView does cover the whole screen width.
Also, the items are layed out as expected when assigning wrap_content or match_parent to the item's android:layout_width and android:layout_height.
For example, when both are set to wrap_content this is the result in the ConstraintLayout:
Here is the source for the broken layout (second screenshot).
MainActivity.java
package com.example.recyclerviewtest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setAdapter(new MyRecyclerViewAdapter());
}
}
MyRecyclerViewAdapter.java
package com.example.recyclerviewtest;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MyRecyclerViewAdapter extends RecyclerView.Adapter {
class ViewHolder extends RecyclerView.ViewHolder {
ViewHolder(View itemView) {
super(itemView);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.recycler_view_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
#Override
public int getItemCount() {
return 3;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="GridLayoutManager"
app:spanCount="2" />
</android.support.constraint.ConstraintLayout>
recycler_view_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:background="#android:color/holo_green_light"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LINE 1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LINE 2" />
</LinearLayout>
To summarize: The layout only breaks when setting a fixed value to android:layout_width or android:layout_height while using a ConstraintLayout.
Try to set your recycler view width to 0dp, add a contraint startToStarOf parent and a contraint endToEndOf parent too. Also, add a contraint horizontalWeight to 1.
Let me know it works.
Related
Hello there i have a recylerview with images where the hieght is wrap_content and width is match_parent just like pintrest but the issue is when the recylerview is loaded the images are not loaded properly it is a mess here is screen shot of it
I know this is becuase im not using a place holder, but even if i add a circular progress bar it will show on each of the image (which i dont want) i want that just like how pintrest load images with one circular progress bar and all images are loaded . im talking about this
How can i achive that functionality
Note : If anyone want more refrence of the code please tell me i will
upload the requested file code
Here is my Code
post_item_container_search.xml // this the layout is for images
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="5dp"
android:layout_marginTop="11dp"
android:layout_marginEnd="5dp"
app:cardBackgroundColor="#color/grey"
app:cardCornerRadius="13dp"
app:cardElevation="1dp"
app:cardMaxElevation="4dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.imageview.ShapeableImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="#string/todo"
app:shapeAppearanceOverlay="#style/RoundedCorner" />
<TextView
android:id="#+id/rankedNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/circular_background_text"
android:fontFamily="#font/roboto"
android:gravity="center"
android:textColor="#color/white"
android:textSize="15sp"
android:textStyle="bold"
tools:ignore="RtlHardcoded" />
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
</RelativeLayout>
PostAdapter_Search.java // adapter class which inflates the recylervew
package com.example.myappnotfinal.AdaptersAndMore;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.example.myappnotfinal.R;
import com.google.android.material.imageview.ShapeableImageView;
import java.util.List;
public class PostAdapter_Search extends RecyclerView.Adapter<PostAdapter_Search.PostViewHolder> {
public static List<Upload> mUploads;
public Context mcontext;
View view;
public PostAdapter_Search(Context context, List<Upload> uploads) {
mUploads = uploads;
mcontext = context;
}
#NonNull
#Override
public PostViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
view = LayoutInflater.from(mcontext).inflate(R.layout.post_item_container_search, parent, false);
return new PostViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PostViewHolder holder, int position) {
Upload uploadCurrent = mUploads.get(position);
Glide.with(mcontext)
.load(uploadCurrent.getmImageUrl())
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.centerCrop()
.fitCenter()
.into(holder.imageView);
holder.textView.setText(String.valueOf(position + 1));
}
#Override
public int getItemCount() {
int limit = 10;
return Math.min(mUploads.size(), limit);
}
public static class PostViewHolder extends RecyclerView.ViewHolder {
ShapeableImageView imageView;
TextView textView;
public PostViewHolder(#NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imageView);
textView = itemView.findViewById(R.id.rankedNumber);
}
}
}
Update 1 // aded FlexBoxLayoutManager
Ok i have aded FlexBoxLayoutManager but there is only one row and i dont know how to add 2 rows in it
Search_Fragment.java
FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager(getContext());
flexboxLayoutManager.setFlexDirection(FlexDirection.ROW);
flexboxLayoutManager.setJustifyContent(JustifyContent.FLEX_END);
postRecyclerView.setLayoutManager(flexboxLayoutManager);
and also can anyone tell me what this line do
.setJustifyContent(JustifyContent.FLEX_END);
Before adding FlexBoxLayoutManager i used this
postRecyclerView.setLayoutManager(
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
);
I'm trying to add a Firebase Recyclerview in my Android App. When I add, all the data is getting fetched from Firestore normally, but when it comes to handle onClick event, it is not working at all.
Things I followed:
Added Interface with method.
Implemented interface in my TipsActivity.java
Here is the code:
TipsActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.paging.PagedList;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.Toast;
import android.util.Log;
import com.firebase.ui.firestore.paging.FirestorePagingOptions;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
public class TipsActivity extends AppCompatActivity implements FirestoreTipsAdapter.OnListItemClick {
FirestoreTipsAdapter firestoreTipsAdapter;
FirebaseFirestore firebaseFirestore;
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tips);
firebaseFirestore = FirebaseFirestore.getInstance();
recyclerView = findViewById(R.id.list);
Query query = firebaseFirestore.collection("DailyTips").document("MyTips").collection("Tips");
PagedList.Config config = new PagedList.Config.Builder()
.setInitialLoadSizeHint(10)
.setPageSize(5)
.build();
FirestorePagingOptions<TipsModel> firestorePagingOptions = new FirestorePagingOptions.Builder<TipsModel>()
.setLifecycleOwner(this)
.setQuery(query,config,TipsModel.class)
.build();
firestoreTipsAdapter = new FirestoreTipsAdapter(firestorePagingOptions,this,this);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(firestoreTipsAdapter);
}
#Override
public void onItemClick() {
Toast.makeText(this, "Show up bruh!", Toast.LENGTH_SHORT).show();
Log.d("AT_LEAST","You should work");
}
}
And here goes my:
FirestoreTipsAdapter.java
package com.mycompany.company;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.firebase.ui.firestore.paging.FirestorePagingAdapter;
import com.firebase.ui.firestore.paging.FirestorePagingOptions;
public class FirestoreTipsAdapter extends FirestorePagingAdapter<TipsModel, FirestoreTipsAdapter.TipsViewHolder> {
private OnListItemClick onListItemClick;
Context context;
public FirestoreTipsAdapter(#NonNull FirestorePagingOptions<TipsModel> options,OnListItemClick onListItemClick,Context context) {
super(options);
this.onListItemClick = onListItemClick;
this.context = context;
}
#Override
protected void onBindViewHolder(#NonNull TipsViewHolder holder, int position, #NonNull TipsModel model) {
holder.title.setText(model.getTitle());
holder.description.setText(model.getDescription());
}
#NonNull
#Override
public TipsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,parent,false);
return new TipsViewHolder(view);
}
public class TipsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView title,description;
public TipsViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.list_title);
description = itemView.findViewById(R.id.list_desc);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "Are you working bro?", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onClick(View v) {
onListItemClick.onItemClick();
}
}
public interface OnListItemClick{
void onItemClick();
}
}
Here is the code of list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="10dp"
android:id="#+id/tipCardView"
app:cardElevation="5dp"
app:cardBackgroundColor="#E2E0EE"
app:cardCornerRadius="5dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="#+id/list_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:background="?attr/selectableItemBackground"
android:padding="16dp">
<TextView
android:id="#+id/list_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textColor="#android:color/black"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/list_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Description" />
</LinearLayout>
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/curveshape"
android:layout_gravity="end|bottom"
android:layout_marginBottom="-30dp"
android:alpha="0.2"
/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/tips"
android:layout_gravity="end|bottom"
android:layout_marginBottom="-10dp"
android:layout_marginRight="25dp"
android:alpha="0.2"
/>
</androidx.cardview.widget.CardView>
Note: I'm able to fetch data from Firestore, it is showing data properly.
Please help. I followed all other answers from Stack Overflow.
In the given setup, the OnClickListener is being set on the ViewHolder's itemView, which will be the root View in its layout, which is the CardView. However, the clickable and focusable attributes set on the LinearLayout cause it to get first grabs on touch events, so it's basically intercepting them before the CardView would handle them to respond to a click. There's no listener on the LinearLayout, though, so nothing happens.
Assuming that you want the entire item View clickable, simply remove the android:clickable="true" and android:focusable="true" attributes from the <LinearLayout>. With no clickable or focusable children, the CardView will then end up registering the click.
If instead you might want only a certain child clickable – e.g., the LinearLayout – then you would set the OnClickListener on that child, rather than the whole CardView. You still wouldn't need those attributes anywhere, though, if that's to be the only clickable child or grandchild. Those attributes usually aren't necessary in basic, relatively flat layouts, like that for your list items.
Is there any way to disable the CardView elevation animation from a recyclerview when an item is changed but to keep the original shadow and item animator?
I've tried to disable the CardView state animator android:stateListAnimator="#null" with no results.
Here's a way to reproduce the issue:
package com.w.cardviewrecyclerviewanim;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
RecyclerView items;
Adapter adapter = new Adapter();
GridLayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
items = findViewById(R.id.items);
layoutManager = new GridLayoutManager(this, 2, LinearLayoutManager.VERTICAL, false);
items.setLayoutManager(layoutManager);
items.setAdapter(adapter);
}
class Holder extends RecyclerView.ViewHolder{
CardView cardView;
public Holder(#NonNull View itemView) {
super(itemView);
cardView = itemView.findViewById(R.id.card_view);
}
void bind (){
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
adapter.notifyItemChanged(getAdapterPosition());
}
});
cardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
return true;
}
});
}
}
class Adapter extends RecyclerView.Adapter<Holder>{
#NonNull
#Override
public Holder onCreateViewHolder(#NonNull ViewGroup viewGroup, int position) {
LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
return new Holder(layoutInflater.inflate(R.layout.item, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull Holder holder, int position) {
holder.bind();
}
#Override
public int getItemCount() {
return 30;
}
}
}
And here's the item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="160dp"
>
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:cardCornerRadius="8dp"
app:cardElevation="5dp"
android:stateListAnimator="#null"
>
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
I have a simple RecyclerViewer that has 30 items and each item has a CardView with 10dp margin and a cardElevation of 5dp just to have some nice shadow.
When an item gets clicked the recyclerview adapter receives a notifyItemChanged(getAdapterPosition()) and on long click all items receives a change event via a notifyItemRangeChanged(0, adapter.getItemCount()) call to the adapter;
With the DefaultItemAnimator whenever an item gets "changed" the CardView shadow gets animated bigger during the transition animation. I want to keep the transition as I'm doing some updates in the item but I don't want to have the shadow/elevation animation.
You can see the outcome here:
https://gph.is/g/ajmNGen
Think that on long click the application moves into a "multi select" mode where all the items have big changes in layout and I want this change to be animated (by the DefaulItemAnimator) and I would like to keep the shadow as set originally.
Any help is really appreciated guys as I'm pulling my hair while dealing with this.
Set a constraint layout inside cardView, then you can clearly see the shadow:-
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="6dp"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
I am attempting to make a basic photo album app for Android TV.
Using recyclerview with glide.
Issue:
When scrolling one by one slowly by pressing dpad down button, recyclerview items gain focus accurately just as expected. But when dpad down button is kept pressed, during fast scroll, recyclerview item easily lose focus and the focus is moved to any focusable view (in this case an edit text) outside the recyclerview and no scrolling is possible until manually focus is moved inside recyclerview again.
Remedies attempted:
1. If I disable image loading by Glide completely (inside onBindViewHolder()), focus is never lost and no matter how fast the scrolling is it always works as expected. This remedy is not useful as images needs to be viewed.
2. If fast scrolling is limited by overriding Activity.onKeyDown method to ignore all key inputs unless 300ms has passed since last keydown it works. Again, this feels very hacky and completely disables fast scroll with is an absolute requirement.
Please note that I have already read the related QA on stackoverflow. Which suggested it's a bug in Android support library LayoutManager code which is not the case here since without glide it works fine.
How to reproduce: Create a fragment like ListFragment (code below) and try fast scrolling by keeping Down Dpad button pressed and you will see that editText constantly getting focused.
Code:
ListFragment.java
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import java.util.Random;
public class ListFragment extends Fragment {
RequestManager glide;
public ListFragment() {
// Required empty public constructor
}
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_list, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = getActivity().findViewById(R.id.my_recycler_view);
glide = Glide.with(this);
layoutManager = new GridLayoutManager(getActivity(),8);
mAdapter = new MyAdapter();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAdapter);
}
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private final String[] imageUrls = {"https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa1821c67c1430401c65/1546365481213/20181208_0034pp2+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa218a922d1c5eb370c5/1546365483758/20181208_0115pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba92340ec9ab2ea3f0f73/1546365229886/20181215_0135pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8880e2e72e38d92a482/1546365075745/20180914_0189+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba885f950b760dd6800a7/1546365086762/20180914_0168pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba9b1032be425c6948ca2/1546365375849/20180818_0014pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa184ae2379d323c4187/1546365481929/20181208_0065pp+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256b9e4fcb574ae612941/1470258368357/20160801_0045.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255d1e4fcb574ae61196f/1470256635728/20160717_0391.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25695e4fcb574ae61273c/1470258368265/20160801_0040.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256dbe4fcb574ae612b71/1470258369606/20160801_0108+pp+810+bw.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257088419c29f345a7500/1470258369115/20160801_0108+pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4f950b760dd6804fe/1546365168544/20181101_0067pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba83270a6adae0b3b6395/1546364992480/20181205_0164pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4575d1f0c318f3727/1546365171139/20181101_0050pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2543dd1758e06589e07f1/1470256544677/20160402_0075+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a253fad1758e06589e040f/1470256190368/20160402_0039+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255fae4fcb574ae611e08/1470258367476/20160717_0444b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2573be4fcb574ae613197/1470258370169/20160801_0123+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257708419c29f345a7ba7/1470258369404/20160801_0272+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25db19f74561d105005de/1470258684806/20160402_0046+810+nik2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/55076c74e4b07b36ea118be0/1470413754677/20141222_0049.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256688419c29f345a6b17/1470258368620/20160721_0097+pp2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255c9d1758e06589e1f5e/1470258367695/20160721_0012+ppb.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c21ac72b8dde5db5879498/1546363401197/20151107_0094+pp+57c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c20eb662cd945cd5b485f5/1546363401197/20151024_1026+pp+810c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/53558987e4b007661e339aa7/1470413754809/20140419_0430_pp1+5x7b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db7f3893fc0e1cdfe1bbb/1482536961660/20160507_0069b+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8019de4bb91b69d5e37/1482537012182/20160904_0012+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8346a496340ce2b8f6e/1482537056393/20160904_0043+pp+810l.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db846d482e9c87e69aa3c/1482537056630/20160904_0071+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db860d2b857ddbd63c824/1482537071373/20160904_0119+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8602e69cf4bac703ff9/1482537081308/20160904_0124+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8828419c2d595b13ee0/1482537109350/20161008_0086+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8923e00be46604ad66c/1482537119283/20161105_0068pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db895b3db2b35c2346e97/1482537128208/20161128_0181+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db89fc534a5283f35edd0/1482537156287/20161203_0126+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8a703596eeb52691ac2/1482537145676/20161206_0101.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa1821c67c1430401c65/1546365481213/20181208_0034pp2+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa218a922d1c5eb370c5/1546365483758/20181208_0115pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba92340ec9ab2ea3f0f73/1546365229886/20181215_0135pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8880e2e72e38d92a482/1546365075745/20180914_0189+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba885f950b760dd6800a7/1546365086762/20180914_0168pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba9b1032be425c6948ca2/1546365375849/20180818_0014pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa184ae2379d323c4187/1546365481929/20181208_0065pp+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256b9e4fcb574ae612941/1470258368357/20160801_0045.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255d1e4fcb574ae61196f/1470256635728/20160717_0391.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25695e4fcb574ae61273c/1470258368265/20160801_0040.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256dbe4fcb574ae612b71/1470258369606/20160801_0108+pp+810+bw.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257088419c29f345a7500/1470258369115/20160801_0108+pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4f950b760dd6804fe/1546365168544/20181101_0067pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba83270a6adae0b3b6395/1546364992480/20181205_0164pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4575d1f0c318f3727/1546365171139/20181101_0050pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2543dd1758e06589e07f1/1470256544677/20160402_0075+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a253fad1758e06589e040f/1470256190368/20160402_0039+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255fae4fcb574ae611e08/1470258367476/20160717_0444b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2573be4fcb574ae613197/1470258370169/20160801_0123+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257708419c29f345a7ba7/1470258369404/20160801_0272+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25db19f74561d105005de/1470258684806/20160402_0046+810+nik2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/55076c74e4b07b36ea118be0/1470413754677/20141222_0049.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256688419c29f345a6b17/1470258368620/20160721_0097+pp2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255c9d1758e06589e1f5e/1470258367695/20160721_0012+ppb.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c21ac72b8dde5db5879498/1546363401197/20151107_0094+pp+57c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c20eb662cd945cd5b485f5/1546363401197/20151024_1026+pp+810c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/53558987e4b007661e339aa7/1470413754809/20140419_0430_pp1+5x7b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db7f3893fc0e1cdfe1bbb/1482536961660/20160507_0069b+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8019de4bb91b69d5e37/1482537012182/20160904_0012+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8346a496340ce2b8f6e/1482537056393/20160904_0043+pp+810l.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db846d482e9c87e69aa3c/1482537056630/20160904_0071+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db860d2b857ddbd63c824/1482537071373/20160904_0119+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8602e69cf4bac703ff9/1482537081308/20160904_0124+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8828419c2d595b13ee0/1482537109350/20161008_0086+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8923e00be46604ad66c/1482537119283/20161105_0068pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db895b3db2b35c2346e97/1482537128208/20161128_0181+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db89fc534a5283f35edd0/1482537156287/20161203_0126+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8a703596eeb52691ac2/1482537145676/20161206_0101.jpg"};
private final RequestOptions options = new RequestOptions().centerCrop();
private final Random random = new Random();
private final Handler handler = new Handler();
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView icon;
public View layout;
ViewHolder(View v) {
super(v);
layout = v;
icon = v.findViewById(R.id.icon);
}
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LayoutInflater inflater = LayoutInflater.from(
parent.getContext());
View v =
inflater.inflate(R.layout.item_recycler_view, parent, false);
MyAdapter.ViewHolder vh = new MyAdapter.ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder holder, final int position) {
final String name = imageUrls[random.nextInt(imageUrls.length - 1)];
//Commenting this out resolves focus loss
glide.load(name).into(holder.icon);
}
#Override
public void onViewRecycled(#NonNull ViewHolder holder) {
super.onViewRecycled(holder);
glide.clear(holder.icon);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
}
}
Layouts:
item_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="#drawable/fg_selectable"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="false"
android:descendantFocusability="blocksDescendants"
android:layout_margin="2dp"
>
<ImageView
android:id="#+id/icon"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="27:41"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="#color/colorPrimaryDark"
tools:src="#tools:sample/avatars"
/>
</android.support.constraint.ConstraintLayout>
fragment_list.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ListFragment"
android:orientation="horizontal"
>
<EditText
android:id="#+id/editText"
android:text="test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:nextFocusDown="#id/editText"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
Why do you need glide.clear() in onViewRecycled? My guess is that it has to do with frequent glide loading and clearing during fast scrolls. Glide may be getting somewhat confused. Also, why not Leanback Library and GridFragment? From my experience it works just fine with Glide and fast scrolling.
Any idea why RecyclerView items get deformed , each consecutive item gets worse?
UPDATE: I'm using CardViews and now there's no view "deformation" but the shadow/elevation height changes.
It seems that elevation gets higher depending on where on the screen the item is located vertically, the shadow grows as the item gets scrolled down. Please see the video here: https://youtu.be/nROYq8rpUMs.
I've set up a new project leaving only the code necessary to demonstrate the issue:
MainActivity.java
package tzig.schm00.masterdetail;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import tzig.schm00.masterdetail.dummy.DummyContent;
import java.util.List;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View recyclerView = findViewById(R.id.item_list);
setupRecyclerView((RecyclerView) recyclerView);
}
private void setupRecyclerView(#NonNull RecyclerView recyclerView) {
recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(DummyContent.ITEMS));
}
public class SimpleItemRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {
private final List<DummyContent.DummyItem> mValues;
public SimpleItemRecyclerViewAdapter(List<DummyContent.DummyItem> items) {
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mIdView.setText(mValues.get(position).id);
holder.mContentView.setText(mValues.get(position).content);
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView mIdView;
public final TextView mContentView;
public DummyContent.DummyItem mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mIdView = (TextView) view.findViewById(R.id.id);
mContentView = (TextView) view.findViewById(R.id.content);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/item_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="tzig.schm00.myapplication.MainActivity" />
</FrameLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/cont_item_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="8dp"
card_view:cardElevation="10dp"
card_view:cardMaxElevation="10dp"
card_view:cardUseCompatPadding="true">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<TextView
android:id="#+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
</LinearLayout>
</android.support.v7.widget.CardView>
New observation: seems like it's a standard behavior. Looks the same with the Image Picker displaying folders using CardViews...
Any help is greatly appreciated!
Thanks!!
This is how it's intended to be according to Material Design: Environment: Light and shadows: Light.
Also see answer https://stackoverflow.com/a/51216164/6685260
Add a background to your RelativeLayout - seems that elevation needs it to work properly. I have tested this with your layout and it does work.
I had the same issue, and in my case the problem was caused by a background drawable which I set in my RecyclerViewAdapter#onBindViewHolder:
// this spoiled the shadows!
cardView.setBackgroundDrawable(ContextCompat.getDrawable(context, myColorResourceId);
After I removed the line above the problem has disappeared!
(To have both a background and nice shadows I used an inner element filling the CardView and applied background to it instead of CardView)