【问题标题】:RecyclerView Layout Manager ManipulationRecyclerView 布局管理器操作
【发布时间】:2017-05-30 06:46:19
【问题描述】:

我有一个回收站视图,它应该显示如下数据(如果位置是偶数则为 1 项,如果位置为奇数则彼此相邻 2 项),老实说,我尝试了又尝试,但我没有这样做。

它应该是这样的

现在是这样的(忽略宽度和高度,看看视频 3 是如何膨胀两次的)

我正在使用 LinearLayoutManager,这是我的适配器:

public class MediaItemsAdapter extends RecyclerView.Adapter<MediaItemsAdapter.RecyclerViewHolder> {

private List<MediaItem> allMediaItems;
private Activity context;
private RecyclerViewOnItemClickListener itemClickListener;

public MediaItemsAdapter(Activity context, List<MediaItem> allMediaItems, RecyclerViewOnItemClickListener itemClickListener ) {

    this.allMediaItems = allMediaItems;
    this.context = context;
    this.itemClickListener = itemClickListener;
}

@Override
public void onBindViewHolder(final RecyclerViewHolder holder, final int position) {

    MediaItem mediaItem = allMediaItems.get(position);

    if(position %2 == 0){ // even

        holder.tvTitle.setText(mediaItem.getTitle());
        holder.tvSummary.setText(mediaItem.getDate());

        try {
            Picasso.with(context)
                    .load(mediaItem.getImageUrl())
                    .into(holder.ivImage, new com.squareup.picasso.Callback() {
                        @Override
                        public void onSuccess() {
                            holder.ivImage.setAlpha((float) 1);
                        }

                        @Override
                        public void onError() {
                            Log.wtf("error", "in loading");
                        }
                    });

        } catch (Exception e) {
            e.printStackTrace();
        }

        holder.ivPlay.setVisibility(mediaItem.isVideo() ? View.VISIBLE : View.GONE);
    }else{ //odd

        holder.tvTitle.setText(mediaItem.getTitle());
        holder.tvSummary.setText(mediaItem.getDate());

        try {
            Picasso.with(context)
                    .load(mediaItem.getImageUrl())
                    .into(holder.ivImage, new com.squareup.picasso.Callback() {
                        @Override
                        public void onSuccess() {
                            holder.ivImage.setAlpha((float) 1);
                        }

                        @Override
                        public void onError() {
                            Log.wtf("error", "in loading");
                        }
                    });

        } catch (Exception e) {
            e.printStackTrace();
        }

        holder.ivPlay.setVisibility(mediaItem.isVideo() ? View.VISIBLE : View.GONE);

        try{

            MediaItem secondMediaItem = allMediaItems.get(position + 1);
            holder.tvSecondTitle.setText(secondMediaItem.getTitle());
            holder.tvSecondSummary.setText(secondMediaItem.getDate());

            try {
                Picasso.with(context)
                        .load(secondMediaItem.getImageUrl())
                        .into(holder.ivSecondImage, new com.squareup.picasso.Callback() {
                            @Override
                            public void onSuccess() {
                                holder.ivSecondImage.setAlpha((float) 1);
                            }

                            @Override
                            public void onError() {
                                Log.wtf("error", "in loading");
                            }
                        });

            } catch (Exception e) {
                e.printStackTrace();
            }

            holder.ivSecondPlay.setVisibility(secondMediaItem.isVideo() ? View.VISIBLE : View.GONE);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

@Override
public int getItemViewType(int position) {
    return position %2 == 0 ? 0 : 1;
}

@Override
public int getItemCount() {
    return this.allMediaItems.size();
}


public interface RecyclerViewOnItemClickListener {
    void onItemClicked(View v, int position);
}

public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View layoutView;

    if (viewType == 0 ){

        layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.even_media_layout, parent, false);
        RecyclerViewHolder rcv = new RecyclerViewHolder(layoutView);
        return (rcv);
    }else{

        layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.odd_media_layout, parent, false);
        RecyclerViewHolder rcv = new RecyclerViewHolder(layoutView);
        return (rcv);
    }
}

public class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    private TextView tvTitle, tvSecondTitle, tvSummary, tvSecondSummary;
    private ImageView ivImage, ivSecondImage;
    private ImageButton ivPlay, ivSecondPlay;

    protected View itemView;

    public RecyclerViewHolder(View itemView) {
        super(itemView);
        this.itemView = itemView;
        this.itemView.setOnClickListener(this);

        tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
        tvSecondTitle = (TextView) itemView.findViewById(R.id.tvSecondTitle);
        tvSummary = (TextView) itemView.findViewById(R.id.tvSummary);
        tvSecondSummary = (TextView) itemView.findViewById(R.id.tvSecondSummary);

        ivImage = (ImageView) itemView.findViewById(R.id.ivImage);
        ivSecondImage = (ImageView) itemView.findViewById(R.id.ivSecondImage);

        ivPlay = (ImageButton) itemView.findViewById(R.id.ivPlay);
        ivSecondPlay = (ImageButton) itemView.findViewById(R.id.ivSecondPlay);
    }

    @Override
    public void onClick(View view) {
        itemClickListener.onItemClicked(view, getLayoutPosition());
    }
}
}

如何防止数据复制,如何告诉数组列表对象3已经膨胀了?有没有比 LinearLayoutManager 更好的方法

问候。

【问题讨论】:

  • 您好,欢迎来到 Stack Overflow。如果您提供minimal reproducible example,您的问题可能会引起更多兴趣。就目前而言,这个问题太复杂了,有太多不相关的部分。

标签: android android-recyclerview layout-manager


【解决方案1】:

用户 GridLayoutManage 到您的 RecyclerView 并像这样设置跨度大小查找。

    GridLayoutManager glm = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
    glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){

        @Override
        public int getSpanSize(int position) {
            return position % 3 == 0 ? 2 : 1;
        }
    });

【讨论】:

  • 非常感谢
【解决方案2】:

我建议你使用Adapter delegates,显然你可以不用它,但它会帮助你进一步的开发。

Here你可以阅读它

您应该创建 2 个委托,然后在 isForViewType() 返回布尔值,具体取决于提供的条件 return position % 2 == 1 并在 onCreateViewHolder() 返回相关的 ViewHolder(您将拥有 2 个)

【讨论】:

    【解决方案3】:

    你的计算在这里出错了

    return position %2 == 0 ? 0 : 1;

    看到这个

    |0| 1|2 |3| 4|5 |6| 7|8

    如果你仔细观察项目的出现,3的倍数的项目是全宽的。

    所以基本上你的计算应该是这样的

    return position % 3 == 0 ? 0 : 1;

    再解释一下,偶数行有两个项目,但你计算的是偶数个项目。

    也更正这部分代码

    @Override
    public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
    
        final int adapterPosition = holder.getAdapterPosition();
        MediaItem mediaItem = allMediaItems.get(adapterPosition);
    
        if(adapterPoaition % 3 == 0){ // every third item
           //your codes
        }
        //remaining codes
    }
    

    首先你应该使用适配器位置而不是作为参数传递的视图位置。接下来的事情是你也必须在这里使用第三个位置而不是第二个

    附:你的适配器代码有点乱,不确定是否更正 这个计算会给你正确的结果,直到你这样做 少量代码清理。

    【讨论】:

    • 我试过这个返回位置 % 3 == 0 ? 0:1,但我所拥有的是(第一行一个项目 vid 1,第二行 vid2 和 vid3,第三行 vid3,以及它旁边的空布局)为什么视频 3 总是复制
    • 我已经说过了,你的适配器代码太大,目前无法调试,我认为你的适配器中还有很多计算错误。
    • 好的,我发现了其他错误,在答案中更新它