StaggeredGridLayoutManager错位(二)

StaggeredGridLayoutManager dislocation (2)

同样的问题,不知道这算不算重复。

我对 Android 的 StaggeredGridLayoutManager 有疑问。问题的描述和StaggeredGridLayoutManager dislocation.

差不多

这是屏幕截图(对审查感到抱歉,这些是 CardViews):

适配器:

    public class ProductItemStaggeredAdapter extends RecyclerView.Adapter<ViewHolderRVProductItem> {
    public ProductItemStaggeredAdapter(RealmResults<ProductItem> items, int theme) {
        mItems = items;
        this.theme = theme;
        setHasStableIds(true);
    }

    @Override
    public ViewHolderRVProductItem onCreateViewHolder(final ViewGroup parent, final int viewType) {
        Context context = parent.getContext();
        int blackGrey1 = ContextCompat.getColor(context, R.color.black_grey1);
        int white = ContextCompat.getColor(context, R.color.white);
        LayoutInflater inflater = LayoutInflater.from(context);
        View view;

        ViewHolderRVProductItem vh = null;
        switch (viewType) {
            case 100:
                /** Error **/
                view = inflater.inflate(R.layout.item_retry, parent, false);
                StaggeredGridLayoutManager.LayoutParams lp3 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
                lp3.setFullSpan(true);
                view.setLayoutParams(lp3);
                view.setOnClickListener(retryClickListener);
                vh = new ViewHolderRVProductItem(view);
                break;
            case 101:
                /** Loading **/
                view = inflater.inflate(R.layout.item_loading, parent, false);
                StaggeredGridLayoutManager.LayoutParams lp4 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
                lp4.setFullSpan(true);
                view.setLayoutParams(lp4);
                vh = new ViewHolderRVProductItem(view);
                break;
            case Banner.ONE:
                /**
                 * This banner occupies 1 column of the screen
                 * The height is set programmatically based on screen width
                 *
                 * Product image ratio is 32 x 15
                 */
                view = inflater.inflate(R.layout.item_banner_big, parent, false);
                view.setOnClickListener(productClickListener);
                StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
                lp.setFullSpan(true);
                view.setLayoutParams(lp);

                view.setOnClickListener(productClickListener);

                vh = new ViewHolderRVProductItem(view);
                break;
            case Banner.TWO:
                /**
                 * This banner occupies 1 column of the screen
                 * The height is smaller than BANNER_ONE
                 * The height is set programmatically based on screen width
                 */
                view = inflater.inflate(R.layout.item_banner_big, parent, false);
                view.setOnClickListener(productClickListener);
                StaggeredGridLayoutManager.LayoutParams lp2 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
                lp2.setFullSpan(true);
                view.setLayoutParams(lp2);

                view.setOnClickListener(productClickListener);

                vh = new ViewHolderRVProductItem(view);
                break;
            case Banner.THREE:
                /**
                 * This banner occupies 3 column of the screen
                 * The height is set programmatically based on screen width
                 */
                view = inflater.inflate(R.layout.item_banner_long_rect, parent, false);
                view.setOnClickListener(productClickListener);
                vh = new ViewHolderRVProductItem(view);
                break;
            case Banner.FOUR:
                /**
                 * This banner occupies 3 column of the screen
                 * The height is smaller than BANNER_THREE
                 * The height is set programmatically based on screen width
                 */
                view = inflater.inflate(R.layout.item_banner_long_rect, parent, false);
                view.setOnClickListener(productClickListener);
                vh = new ViewHolderRVProductItem(view);
                break;
            default: /** ProductItem.BANNER_FIVE **/
                /**
                 * This banner occupies 2 column of the screen
                 * The height is set programmatically based on screen width
                 */
                view = inflater.inflate(R.layout.item_banner_recommended, parent, false);
                view.setOnClickListener(productClickListener);
                vh = new ViewHolderRVProductItem(view);
                break;
        }

        /** Set image ratio **/
        if (vh.productImage != null) {
            final ViewHolderRVProductItem finalVh = vh;
            vh.itemView.post(new Runnable() {
                @Override
                public void run() {
                    setImageRatio(finalVh.productImage, viewType, finalVh.productImage.getWidth());
                }
            });
        }

        return vh;
    }

    @Override
    public void onBindViewHolder(final ViewHolderRVProductItem holder, final int position) {
        if (holder == null) return;

        final Context context = holder.itemView.getContext();
        final ProductItem item = mItems.get(position);

        holder.itemView.setTag(item);

        final int bannerType = holder.getItemViewType();
        final Banner banner = bannerType == Banner.ONE ? item.getBanner1() : (bannerType == Banner.FIVE ? item.getBanner5() : (bannerType == Banner.TWO ? item.getBanner2() : (bannerType == Banner.THREE ? item.getBanner3() : item.getBanner4())));

        if (banner != null && holder.productImage != null) {
            holder.productImage.post(new Runnable() {
                @Override
                public void run() {
                    float width = holder.productImage.getWidth();
                    float height = holder.productImage.getHeight();
                    Picasso.with(context)
                            .load(banner.getImageURL6())
                            .resize((int) width, (int) height)
                            .into(holder.productImage);
                }
            });
        }
    }

    private void setImageRatio(ImageView imgview, int bannerType, int width) {
        Context context = imgview.getContext();
        switch (bannerType) {
            case Banner.ONE:
                /** Product image ratio is 32 x 15 **/
                float height = (15f / 32f) * width;
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imgview.getLayoutParams();
                params.width = width;
                params.height = (int) height;
                imgview.setLayoutParams(params);
                break;
            case Banner.TWO:
                /** Product image ratio is 11 x 3 **/
                float height1 = (3f / 11f) * width;
                LinearLayout.LayoutParams params1 = (LinearLayout.LayoutParams) imgview.getLayoutParams();
                params1.width = width;
                params1.height = (int) height1;
                imgview.setLayoutParams(params1);
                break;
            case Banner.THREE:
                /** Product image ratio: 27 x 40 **/
                float height2 = (40f / 27f) * width;
                RelativeLayout.LayoutParams params2 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
                params2.width = (int) width;
                params2.height = (int) height2;
                imgview.setLayoutParams(params2);
                break;
            case Banner.FOUR:
                int dip8 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, context.getResources().getDisplayMetrics());

                /** Product image ratio: 1 x 1 **/
                int size = (int) width - dip8;
                RelativeLayout.LayoutParams params3 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
                params3.width = size;
                params3.height = size;
                params3.leftMargin = dip8;
                params3.topMargin = dip8;
                params3.rightMargin = dip8;
                imgview.setLayoutParams(params3);
                break;
            case Banner.FIVE:
                /** Product image ratio: 162 x 71 **/
                float height3 = (71f / 162f) * width;
                RelativeLayout.LayoutParams params4 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
                params4.width = (int) width;
                params4.height = (int) height3;
                imgview.setLayoutParams(params4);
                break;
        }
    }
}

previous problem 和这个问题所做的事情是以编程方式更改 ImageView 宽度和高度。为什么更改 View 的布局会对 RecyclerView 产生影响?

我找到了最终解决方案。我没有使用 previous solution,而是找到了罪魁祸首:

    final ViewHolderRVProductItem finalVh = vh;
        vh.itemView.post(new Runnable() {
            @Override
            public void run() {
                setImageRatio(finalVh.productImage, viewType, finalVh.productImage.getWidth());
            }
        });

我认为不建议在适配器中使用 post 修改 ImageView 的大小。我现在正在使用 AspectRatioImageView 并且运行顺利。