View recycling ViewGolder

I have a view of recyclers with different holders.

Several view holders have images that I pass to Glide to display the images.

The problem is that when the recycler view starts to recycle the views, the width / height of the image is the kind of processed image that then incorrectly displays the image.

Here is my ImageView:

<ImageView android:id="@+id/image" android:layout_marginTop="@dimen/feed_item_margin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"/> 

It is transmitted to Glide

 Glide.with(itemView.getContext()) .load(Uri.parse(MediaUtils .getMedia(feedContent).getMediaUrl())) .placeholder(R.drawable.placeholder) .diskCacheStrategy(DiskCacheStrategy.SOURCE) .crossFade().into(image); 

This works well until Recyclerview starts recycling, so the first image in recyclerview looks the way it should look.

enter image description here

however, when you bounce off an element and scroll backward, it looks like this:

enter image description here

So, the image is distorted and is not the full width of the parent element.

I want the image to display the contents of the content, because all the images will be of different heights, etc. To test this, I added this line holder.setIsRecyclable(false); to prevent reuse of this particular holder, and all images displayed as they should, however, as expected, this gave a jarring effect.

So, I tried to reset the image view settings in the OnViewRecycled method as follows:

 @Override public void onViewRecycled(AbstractHolder viewHolder){ super.onViewRecycled(viewHolder); int position = viewHolder.getAdapterPosition(); IFeedContent content = mFeedContentList.get(position); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.setMargins(0, (int) Utils.dpTopx(mContext,10),0,0); params.gravity = Gravity.CENTER; if(isImage(content)){ viewHolder.getImageView().setImageURI(null); viewHolder.getImageView().setImageDrawable(null); viewHolder.getImageView().setImageResource(0); viewHolder.getImageView().setLayoutParams(params); } } 

In this, I recreate params in xml, but it does not work. The isImage() method simply checks the image type of the object.

Can anyone help with this? This is very frustrating.

Any help on this is appreciated.

EDIT Adapter Added

 public class ContentFeedAdapter extends RecyclerView.Adapter<AbstractHolder> { private List<IFeedContent> mFeedContentList; private Context mContext; private Activity mMainActivity; private UserHomeFragment mUserHomeFragment; private UserStreamFragment mUserStreamFragment; private AbstractHolder mAbstractHolder; private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> mThumbnailViewToLoaderMap; private ArrayList<MyMediaPlayer> mMediaPlayerList = new ArrayList<>(); public ContentFeedAdapter(Context ctx, List<IFeedContent> contentList, Activity mainActivity, UserHomeFragment userHomeFragment, UserStreamFragment userStreamFragment){ this.mContext = ctx; this.mFeedContentList = contentList; this.mMainActivity = mainActivity; this.mThumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>(); this.mUserHomeFragment = userHomeFragment; this.mUserStreamFragment = userStreamFragment; } @Override public AbstractHolder onCreateViewHolder(ViewGroup parent, int viewType) { mAbstractHolder = createAbstractHolder(viewType, parent); return mAbstractHolder; } @Override public void onBindViewHolder(final AbstractHolder holder, final int position) { final IFeedContent content = mFeedContentList.get(position); holder.bindData(content); if((content.getMedia()!=null) && !content.getMedia().isEmpty()){ String mimeType = MediaUtils.getMedia(content).getMimeType(); if(mimeType.contains(mContext.getString(R.string.video)) || mimeType.contains(mContext.getString(R.string.audio)) && !mimeType.contains(mContext.getString(R.string.youtube))){ final ProgressBar progressBar = holder.getProgress(); final ImageView playButton = holder.getPlayImage(); final Button retryButton = holder.getRetryImage(); final RelativeLayout playerOverLay = holder.getPlayerOverlay(); final ImageView mediaThumb = holder.getMediaThumbnail(); final MyMediaPlayer player = new MyMediaPlayer(mContext, holder.getTextureView(), holder.getMediaControllerAnchor(), holder.getProgress(), mimeType, MyConstants.SEEK_TO_DEFAULT, retryButton, playButton, playerOverLay, mediaThumb); player.setRecyclerViewPosition(position); mMediaPlayerList.add(player); playButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { player.startVideo(MediaUtils.getMedia(content).getMediaUrl()); holder.getPlayImage().setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); } }); } } } /** * Release all holders used for the * thumbnail views */ public void releaseYouTubeHolders(){ mAbstractHolder.releaseHolders(); } @Override public int getItemViewType(int position){ int viewType = -1; //Instantiate ViewHolder Utils // viewType = ViewHolderUtils.selectViewHolder(mFeedContentList.get(position)); return viewType; } @Override public int getItemCount() { return mFeedContentList.size(); } @Override public void onViewRecycled(AbstractHolder viewHolder){ super.onViewRecycled(viewHolder); int position = viewHolder.getAdapterPosition(); IFeedContent content = mFeedContentList.get(position); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.setMargins(0, (int) Utils.dpTopx(mContext,10),0,0); params.gravity = Gravity.CENTER; if(isImage(content)){ viewHolder.getImageView().setImageURI(null); viewHolder.getImageView().setImageDrawable(null); viewHolder.getImageView().setImageResource(0); viewHolder.getImageView().setLayoutParams(params); } } /** * Create instance of * compatible viewholder * * @param viewType * @param parent * @return */ private AbstractHolder createAbstractHolder(int viewType, ViewGroup parent) { AbstractHolder holder = null; switch (viewType) { case MyConstants.HOLDER_TYPE_1: holder = ViewHolder_Var1.create(parent, mUserHomeFragment, mUserStreamFragment); break; case MyConstants.HOLDER_TYPE_2: holder = ViewHolder_Var2.create(parent, mUserHomeFragment, mUserStreamFragment); break; case MyConstants.HOLDER_TYPE_3: holder = ViewHolder_Var3.create(parent, mUserHomeFragment, mUserStreamFragment); Li(getClass().getSimpleName(), "HOLDER 3"); //holder.setIsRecyclable(false); break; case MyConstants.HOLDER_TYPE_4: holder = ViewHolder_Var4.create(parent, mUserHomeFragment, mUserStreamFragment); Li(getClass().getSimpleName(), "HOLDER 4"); break; case MyConstants.HOLDER_TYPE_5: holder = ViewHolder_Var5.create(parent, mUserHomeFragment, mUserStreamFragment); Li(getClass().getSimpleName(), "HOLDER 5"); break; case MyConstants.HOLDER_TYPE_6: holder = ViewHolder_Var6.create(parent, mUserHomeFragment, mUserStreamFragment); Li(getClass().getSimpleName(), "HOLDER 6"); break; case MyConstants.HOLDER_TYPE_7: holder = ViewHolder_Var7.create(parent, mUserHomeFragment, mUserStreamFragment); Li(getClass().getSimpleName(), "HOLDER 7"); break; case MyConstants.HOLDER_TYPE_8: holder = ViewHolder_Var8.create(parent, mUserHomeFragment, mUserStreamFragment); Li(getClass().getSimpleName(), "HOLDER 8"); break; case MyConstants.HOLDER_TYPE_9: holder = ViewHolder_Var9.create(parent, mUserHomeFragment, mUserStreamFragment); break; case MyConstants.HOLDER_TYPE_10: holder = ViewHolder_Var10.create(parent, mThumbnailViewToLoaderMap, mUserHomeFragment, mUserStreamFragment); } return holder; } private boolean isImage(IFeedContent contentItem) { if (MediaUtils.getMedia(contentItem) != null) { String mimeType = MediaUtils.getMedia(contentItem).getMimeType(); if (mimeType.contains("image")) { Li(getClass().getSimpleName(), "IMAGE HERE"); return true; } else { Li(getClass().getSimpleName(), "NO IMAGE HERE"); } } return false; } } 

EDIT 2 ViewHolder 3

 public class ViewHolder_Var3 extends AbstractHolder { @Bind(R.id.text_holder1) TextView heading; @Bind(R.id.text_holder2) TextView body; @Bind(R.id.image)ImageView image; @Bind(R.id.tabs_layout)LinearLayout tabsLayout; @Bind(R.id.hot)TextView hot; @Bind(R.id.comments)TextView children; @Bind(R.id.gif_label)TextView gifTag; @Bind(R.id.user_name)TextView userName; @Bind(R.id.tag1)TextView tag1; @Bind(R.id.tag2)TextView tag2; @Bind(R.id.tag3)TextView tag3; @Bind(R.id.profile_pic) SimpleDraweeView profilePic; private boolean mEllipsize; private boolean mExpanded; private UserHomeFragment mUserHomeFragment; private UserStreamFragment mUserStreamFragment; public ViewHolder_Var3(View itemView, UserHomeFragment userHomeFragment, UserStreamFragment userStreamFragment) { super(itemView); ButterKnife.bind(this, itemView); mUserHomeFragment = userHomeFragment; this.mUserStreamFragment = userStreamFragment; } @Override public void bindData(final IFeedContent feedContent) { userName.setText(feedContent.getAuthor().getDisplayName()); image.setImageResource(0); image.setImageDrawable(null); image.setImageURI(null); TextView [] tagsArray = {tag1, tag2, tag3}; if (feedContent.getName() != null) { heading.setText(feedContent.getName()); } else { heading.setText(feedContent.getUrl()); } if (feedContent.getName() != null) { body.setText((feedContent.getMessage())); } else { body.setText(feedContent.getUrl()); } Log.i(ViewHolder_Var3.class.getSimpleName(), "Number of lines: " + String.valueOf(body.getLineCount())); if(!MediaUtils.getMedia(feedContent).getMimeType().equals("image/gif")){ gifTag.setVisibility(View.GONE); Glide.with(itemView.getContext()).load(Uri.parse(MediaUtils.getMedia(feedContent).getMediaUrl())).placeholder(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.SOURCE).crossFade().into(image); }else { Glide.with(itemView.getContext()).load(Uri.parse(MediaUtils.getMedia(feedContent).getMediaUrl())).asGif().placeholder(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.RESULT).crossFade().into(image); } displayProfilePic(feedContent, profilePic); Glide.with(itemView.getContext()).load(Uri.parse(MediaUtils.getMedia(feedContent).getMediaUrl())).placeholder(R.drawable.placeholder).diskCacheStrategy(DiskCacheStrategy.ALL).crossFade().into(image); if(mUserHomeFragment==null){ userName.setEnabled(false); profilePic.setEnabled(false); }else{ userName.setEnabled(true); profilePic.setEnabled(true); } userName.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivityForResult(mUserHomeFragment, feedContent.getAuthor().getId(), feedContent.getParentId()); } }); profilePic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivityForResult(mUserHomeFragment, feedContent.getAuthor().getId(), feedContent.getParentId()); } }); long hotAmt = feedContent.getLikeCount() - feedContent.getDislikeCount(); hot.setText(String.valueOf(hotAmt)); children.setText(String.valueOf(feedContent.getChildCount())); List<String> tagsList = feedContent.getTags(); populateTags(tagsList, tagsArray); // if (feedContent.getTags().size() > 0) addTags(tags, tabsLayout); ViewTreeObserver vto = body.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewTreeObserver obs = body.getViewTreeObserver(); obs.removeOnGlobalLayoutListener(this); Layout layout = body.getLayout(); if(layout!=null){ int lines = layout.getLineCount(); if(lines>0){ if(layout.getEllipsisCount(lines-1)>0){ mEllipsize = true; } } } } }); body.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mEllipsize) { if (!mExpanded) { ObjectAnimator animation = ObjectAnimator.ofInt(body, "maxLines", 20); //animation.setInterpolator(new BounceInterpolator()); animation.setDuration(200).start(); // Toast.makeText(itemView.getContext(), "I AM CLICKED", Toast.LENGTH_LONG).show(); mExpanded = true; } else { ObjectAnimator animation = ObjectAnimator.ofInt(body, "maxLines", 4); //animation.setInterpolator(new BounceInterpolator()); animation.setDuration(200).start(); // Toast.makeText(itemView.getContext(), "I AM CLICKED", Toast.LENGTH_LONG).show(); mExpanded = false; } } } }); } @Override public ImageView getImageView(){ return image; } public static ViewHolder_Var3 create(ViewGroup parent, UserHomeFragment homeFragment, UserStreamFragment userStreamFragment){ View root = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_content_item_layout_var3, parent, false); return new ViewHolder_Var3(root, homeFragment, userStreamFragment); } } 
+5
source share
4 answers

Add this line

 android:adjustViewBounds="true" 

in imageview in the layout file will automatically resize the image.

when sliding .crossFade() to .fitCenter()

+17
source

I ran into the same problem and I solved it as shown below

 Glide.with(mContext) .load(model.getImage()) .asBitmap() .fitCenter() .placeholder(R.drawable.ic_placeholder) .error(R.drawable.ic_placeholder) .into(holder.ivImage); 

I just added .asBitmap () and .fitCenter (), the problem is resolved.

+7
source

you must set the width of the image in onBindViewHolder

eg:

 yourImageView.getLayoutParams().width = GetScreenWidthPx(); public int GetScreenWidthPx() { DisplayMetrics displayMetrics = MyApp.GetContext().getResources().getDisplayMetrics(); return displayMetrics.widthPixels - DpToPx(your_margin_in_dp); } public static int DpToPx(int dp) { DisplayMetrics displayMetrics = MyApp.GetContext() .getResources() .getDisplayMetrics(); return (int) (dp * displayMetrics.density + 0.5f); } 
+1
source

1. add android:adjustViewBounds="true" to ImageView

 <ImageView android:id="@+id/img_item_my_show_img" android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:src="@drawable/backgrund_banner"/> 

2. Change the following code for Glide

 Glide.with(context).asBitmap().load(imgUrl) .apply(RequestOptions() .fitCenter() .placeholder(R.drawable.default_img) .error(R.drawable.error_img)) .into(ImageView) 
0
source

Source: https://habr.com/ru/post/1234282/


All Articles