RecyclerView展示多类型item高级用法

通常,我们在展示列表时,列表中的数据类型是多种类型的,而较多时候,多种数据类型包括两级结构,一级是公共部分,包括头像、标题、时间等,二级是具体的内容部分,内容可能是图片、视频、九宫格或者横向列表等。在使用RecyclerView展示时,传统的做法是每个数据类型Type写一个布局,然后根据不同Type写不同ViewHolder,这种写法重复的代码太多,而且比如要是修改标题title,则就要在每个ViewHolder中修改代码,工作量较大。另外一种做法是,将公共部分抽出来写一个公共的BaseContentViewHolder,然后其他具体的内容ViewHolder继承BaseContentViewHolder,这种做法能够解决大量重复的代码问题,但是每个item的布局都要写公共部分的布局,仍旧很不优雅。本文将在前述两种方案的基础上加以改进,给出一种更优雅的方法,本文的关键是通过使用FrameLayout将二级内容部分动态加载,所以当有新类型数据时,每次只需要编写二级内容相关代码即可。

 

(一)公共部分布局base_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <View
        android:layout_width="match_parent"
        android:layout_height="5dp"
        android:background="#F1F0F0"
        />


    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="14dp"
        android:layout_marginRight="14dp"
        android:layout_marginTop="10dp"
        >


        <RelativeLayout
            android:id="@+id/head_rl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >

//一级头像
            <ImageView
                android:id="@+id/head_imageView"
                style="@style/MyFollowUserImageMode"
                android:src="@mipmap/ic_avatar_default_in_profile"
                />

//一级用户名
            <TextView
                android:id="@+id/user_name_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@id/head_imageView"
                android:text=""
                android:layout_marginLeft="5dp"
                android:textColor="@color/swipe_night"
                android:textSize="15sp"
                android:includeFontPadding="false"
                />


//一级时间
            <TextView
                android:id="@+id/date_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:textSize="13sp"
                android:textColor="@color/b3"
                android:text=""
                android:layout_below="@id/user_name_tv"
                android:layout_toRightOf="@id/head_imageView"
                android:includeFontPadding="false"
                />

        </RelativeLayout>


     //一级标题
        <TextView
            android:id="@+id/title_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textSize="15sp"
            android:layout_marginTop="8dp"
            android:textColor="#398CE7"
            android:maxLines="1"
            android:ellipsize="end"
            />

      //加载二级内容
        <FrameLayout
            android:id="@+id/content_fl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            >
        </FrameLayout>


    </LinearLayout>

</LinearLayout>

公共部分的布局包括头像、用户名、时间、标题等一级内容以及加载具体不同数据的一个FrameLayout,FrameLayout是加载具体不同数据的,如图片、视频、九宫格、横向列表等。本文假设需要加载的数据类型包括图片、视频、显示图片的九宫格。

 

(二)二级内容布局

图片布局:image_item_layout:

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_img_iv"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    >
</ImageView>

视频布局:video_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <ImageView
        android:id="@+id/video_bg"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="fitXY" />

    <ImageView
        android:id="@+id/play_iv"
        android:layout_width="42dp"
        android:layout_height="42dp"
        android:layout_centerInParent="true"
        android:src="@mipmap/ic_media_play_in_list" />

</RelativeLayout>

视频布局截图

 

九宫格布局:gridview_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<GridView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/grid_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:numColumns="3"
    android:horizontalSpacing="7dp"
    android:verticalSpacing="7dp" >
</GridView>

这里使用的是GridView控件,也可以使用RecyclerView。

 

(三)适配器Adapter:

本方案的核心是适配器部分,所以只贴出适配器的核心代码以及其他一些核心代码,其他不影响阅读及理解的代码将不贴出来。

以下BaseSuperRecyclerViewAdapter是继承自RecyclerView.Adapter的基类Adapter,不影响阅读及理解,将不贴出BaseSuperRecyclerViewAdapter的代码,AdviseInfoEntity是实体数据类,将不贴出代码。

public class AdviseListAdatper extends BaseSuperRecyclerViewAdapter<AdviseInfoEntity> {

    public AdviseListAdatper(@NonNull SuperRecyclerView superRecyclerView) {
        super(superRecyclerView);
    }


//对应 getItemViewType(int position)方法
    @Override
    public int getMyItemViewType(int position) {
        AdviseInfoEntity adviseInfoEntity = getDataList().get(position);
        return adviseInfoEntity.getTypeContent();
    }


//对应 onCreateViewHolder(ViewGroup parent, int viewType)方法
    @Override
    public FrameViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType) {
        View root = LayoutInflater.from(getContext()).inflate(R.layout.base_item_layout, parent, false);

        ContentHolder subViewHolder = null;
        switch (viewType){
//视频类型
            case AdviseInfoEntity.VIDEO_CONTENT_TYPE:
                subViewHolder = new VideoViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.video_item_layout, parent, false));
                break;
//九宫格类型
                subViewHolder = new GridViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.gridview_item_layout, parent, false));
                break;
//图片类型
            case AdviseInfoEntity.PIC_CONTENT_SINGLE_TYPE:
                subViewHolder =  new ImageViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.image_item_layout, parent, false));

                break;
        }

        return new FrameViewHolder(root,subViewHolder);
    }

    @Override
    public void onBindMyViewHolder(BaseRecyclerViewHolder holder, int position) {
        FrameViewHolder frameViewHolder = (FrameViewHolder)holder;
        AdviseInfoEntity data = getDataList().get(position);
//ImageLoader是封装的glide,不展示代码;ic_avatar_default是缺省图
        ImageLoader.getInstance().loadCircleImage(getContext(), data.getAvatar(), frameViewHolder.headImageView, R.mipmap.ic_avatar_default, R.mipmap.ic_avatar_default);
     
        frameViewHolder.userNameTv.setText(data.getRelateName());

        frameViewHolder.dateTv.setText(DateUtil.stamp2Date(data.getCreateTime()));
        if (TextUtils.isEmpty(data.getTitle())){
            frameViewHolder.titleTv.setVisibility(View.GONE);
        }else {
            frameViewHolder.titleTv.setVisibility(View.VISIBLE);
            frameViewHolder.titleTv.setText(data.getTitle());
        }


        //有视频
        if (data.getTypeContent() == AdviseInfoEntity.VIDEO_CONTENT_TYPE){
            ((VideoViewHolder)frameViewHolder.subViewHolder).show(getContext(),data,position);
        } else if (data.getTypeContent() == AdviseInfoEntity.PIC_LIST_CONTENT_TYPE){
            //九宫格
            ((GridViewHolder)frameViewHolder.subViewHolder).show(getContext(),data,position);
        }else if (data.getTypeContent() == AdviseInfoEntity.PIC_CONTENT_SINGLE_TYPE){
            //单图
            ((ImageViewHolder)frameViewHolder.subViewHolder).show(getContext(),data,position);

        }
    }

    public static class FrameViewHolder extends BaseRecyclerViewHolder {
        @BindView(R.id.head_imageView)
        ImageView headImageView;
        @BindView(R.id.user_name_tv)
        TextView userNameTv;
        @BindView(R.id.date_tv)
        TextView dateTv;
        @BindView(R.id.head_rl)
        RelativeLayout headRl;
        @BindView(R.id.title_tv)
        TextView titleTv;
        @BindView(R.id.content_fl)
        FrameLayout contentFl;


        private ContentHolder subViewHolder;


        public FrameViewHolder(View itemView, ContentHolder subViewHolder) {
            super(itemView);


            if (null!=subViewHolder){
                contentFl.setVisibility(View.VISIBLE);
//将二级视图动态加载
                contentFl.addView(subViewHolder.itemView);
                this.subViewHolder = subViewHolder;
                this.subViewHolder.frameHolder = subViewHolder.frameHolder;
            }else {
                contentFl.setVisibility(View.GONE);
            }

        }
    }

}

 

BaseRecyclerViewHolder代码:

public abstract class BaseRecyclerViewHolder extends RecyclerView.ViewHolder {

    public BaseRecyclerViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

 

ContentHolder是每个二级视图ViewHolder的基类
public class ContentHolder {

   public AdviseListAdatper.FrameViewHolder frameHolder;

    public final View itemView;


    public ContentHolder(@NonNull final View itemView) {
        this.itemView = itemView;
    }


    public @NonNull  AdviseListAdatper.FrameViewHolder getParent() {
        return frameHolder;
    }


    public final int getAdapterPosition() {
        return getParent().getAdapterPosition();
    }


    public final int getLayoutPosition() {
        return getParent().getLayoutPosition();
    }


    public final int getOldPosition() {
        return getParent().getOldPosition();
    }


    public final boolean isRecyclable() {
        return getParent().isRecyclable();
    }


    public final void setIsRecyclable(boolean recyclable) {
        getParent().setIsRecyclable(recyclable);
    }
}

(四)二级视图ViewHolder

(1)视频视图VideoViewHolder代码:

public class VideoViewHolder extends ContentHolder {
   private ImageView  imageView;
   private ImageView  playIv;

    public VideoViewHolder(@NonNull View itemView) {
        super(itemView);
        imageView = itemView.findViewById(R.id.video_bg);
        playIv = itemView.findViewById(R.id.play_iv);
    }

    public void show(Context context, AdviseInfoEntity data, final int position) {
        ImageLoader.getInstance().loadRoundImage16_9(context, data.getImg_url_load(), imageView, (int) PixelUtil.dp2px(0));
    }
}

(2)九宫格视图GridViewHolder代码:

public class GridViewHolder extends ContentHolder{
//ImageGridViewAdapter是继承自系统的BaseAdapter,不展示代码
  private GridView mGridView;
   private ImageGridViewAdapter mAdapter;

    public GridViewHolder(@NonNull View itemView) {
        super(itemView);
        mGridView = itemView.findViewById(R.id.grid_view);
    }

    public void show(Context context, AdviseInfoEntity data, final int position) {
        mAdapter = new ImageGridViewAdapter(context,data.getPicList());
        mGridView.setAdapter(mAdapter);
   }
}

(3)图片视图ImageViewHolder代码:

public class ImageViewHolder extends ContentHolder {
    private ImageView imageIv;
  

    public ImageViewHolder(@NonNull View itemView) {
        super(itemView);
        imageIv = itemView.findViewById(R.id.item_img_iv);
}



    public void show(Context context, AdviseInfoEntity data, final int position) {
        //TopicImage是数据实体类,不影响阅读和理解不展示代码
        TopicImage image = data.getPicList().get(0);
        ImageLoader.getInstance().loadAsBitmapImage2(context, image.getPic_url(), singeIv);

    }

}

(五)使用:

本文的核心是适配器AdviseListAdatper部分,与一般的列表加载适配器使用无异,只需要将数据list传进适配器即可,因此本文不给出具体的使用代码,后续会贴出demo的链接。

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值