RecyclerView 回收的 ViewHolder 中的 ImageView 大小错误

11

我有一个具有不同视图持有者的可回收视图。

其中几个视图持有者具有图像视图,我将其传递到Glide中以显示图像。

问题是,当可回收视图开始回收视图时,ImageView的宽度/高度是被回收的视图,然后错误地显示图片。

这是我的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"/>

这将被传入Glide

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

RecyclerView回收item之前,该方案效果不错。在RecyclerView中的第一张图片正确显示:

enter image description here

然而,当你滚动到远离该item并再次滚回时,图片会变成这样:

enter image description here

因此,图片已经变形,不是父容器的完整宽度。

我想让ImageView根据实际内容自适应大小,因为所有的图片都可能是不同的高度等等... 为了测试这个想法,我添加了这一行代码 holder.setIsRecyclable(false);来防止对这个特定的holder进行回收,这样所有的图片都能正常显示,但是,这给人以不自然的感觉。

所以我尝试在 OnViewRecycled 方法中重置ImageView的参数,如下所示:

@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);
    }
} 
在这里,我重新创建了XML中的参数,但是它不起作用。方法 isImage() 仅检查对象的MIME类型。
有人可以帮忙吗?这很让人沮丧。
感谢任何对此的帮助。
编辑:添加适配器。
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;
    }

}

编辑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);
    }
}

请将您的适配器代码添加到问题中。 - Mohammad Hossein Gerami
@HosseinGerami 适配器已添加。 - DJ-DOO
1
请参见 https://github.com/bumptech/glide/issues/710 - TWiStErRob
你解决了这个问题吗?@DJ-DOO - Stephen
5个回答

30

添加这行内容

android:adjustViewBounds="true"

将布局文件中的 imageview 中添加图片后,它会自动调整大小。

在 Glide 中,将 .crossFade() 改为 .fitCenter()


7

我遇到了同样的问题,我解决方法如下:

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

我刚刚添加了.asBitmap()和.fitCenter(),问题已解决。


对我没用,必须添加android:adjustViewBounds="true"才能工作。 - Daniel Silva

2

1. 在 ImageView 中添加 android:adjustViewBounds="true"

<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. 将以下代码更改为Glide

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

1

你必须在onBindViewHolder中设置图片的宽度。

例如:

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);
}

那么如何确保图像正确显示呢?它们的高度也不同。此外,还有10个不同的视图持有者。 - DJ-DOO
你必须使用holder.getItemViewType()检查项目的类型。 - Mohammad Hossein Gerami
谢谢您的帮助,您能解释一下您的答案吗?当我进行这个加法时,结果变得更好了,但是现在图像与上下文之间有很大的边距。 - DJ-DOO
编辑后的代码添加了边距。我使用这种方法来防止在加载图像之前和之后图像的宽度和高度跳动。 - Mohammad Hossein Gerami
好的,谢谢。我想了解背后的原因。你传递了什么边距? - DJ-DOO
显示剩余6条评论

0

尝试给您的RecyclerView的项ImageView添加一个属性: android:scaleType="fitXY"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接