I have a recycler view with different View Holders.
A couple of view holders have image views which I pass into Glide to display images.
The problem is, when the recycler view starts recycling views, the imageview width/height are that of the recycled view they then display the image incorrectly.
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"/>
This is passed into 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 the Recyclerview starts Recycling so the first image in the recyclerview looks like this which is how it's meant to look.
however, when you scroll away from the item and scroll back it looks like this:
So the image has become distorted and is not not the full width of the parent.
I want the image view to wrap content because all the images will be different heights etc..
To test this I added this line holder.setIsRecyclable(false);
to prevent recycling of this particular holder and all the images displayed as the should, however, as expected this gave the jarring effect.
So I then tried resetting the params of the image view in the OnViewRecycled
method like so:
@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 the params in the xml but it doesn't work. The method isImage()
this just checks the mimetype of the object.
Can anyone help on this? It's 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);
L.i(getClass().getSimpleName(), "HOLDER 3");
//holder.setIsRecyclable(false);
break;
case MyConstants.HOLDER_TYPE_4:
holder = ViewHolder_Var4.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 4");
break;
case MyConstants.HOLDER_TYPE_5:
holder = ViewHolder_Var5.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 5");
break;
case MyConstants.HOLDER_TYPE_6:
holder = ViewHolder_Var6.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 6");
break;
case MyConstants.HOLDER_TYPE_7:
holder = ViewHolder_Var7.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(getClass().getSimpleName(), "HOLDER 7");
break;
case MyConstants.HOLDER_TYPE_8:
holder = ViewHolder_Var8.create(parent, mUserHomeFragment, mUserStreamFragment);
L.i(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")) {
L.i(getClass().getSimpleName(), "IMAGE HERE");
return true;
} else {
L.i(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);
}
}
Add this line
android:adjustViewBounds="true"
to the imageview
in layout file it will automatically resize image view.
in glide change .crossFade()
to .fitCenter()
I ran into the same issue and i solved it as 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() , Issue Resolved.
you must in onBindViewHolder set width of image
for example:
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 .
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 to Glide
Glide.with(context).asBitmap().load(imgUrl)
.apply(RequestOptions()
.fitCenter()
.placeholder(R.drawable.default_img)
.error(R.drawable.error_img))
.into(ImageView)
来源:https://stackoverflow.com/questions/33283493/recyclerview-recycled-viewholder-image-view-wrong-size