欢迎回来Android入门教程的第九期,上一期学习了简单RecyclerView的使用,那么这一期来介绍多样式布局。

上期传送门:#8 Android入门教程 – RecyclerView(1) – LovelyCat的小站 (lovelycatv.cn)

下期传送门:#10 Android入门教程 – RecyclerView(3) – LovelyCat的小站 (lovelycatv.cn)

那么什么是多样式呢?来举一个例子:

简书

如上图所示的界面中,既有图文项目也有纯文本项目,那么这些是怎么实现的呢?下面一起来学习。

首先我们需要再新建一个布局,作为你的第二样式。这边就不再详细描述了,下面直接放我的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="12dp">
    <ImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:src="@mipmap/ic_launcher"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/reitem2_tv"
            android:layout_marginStart="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="This is Title"
            android:textSize="18sp"
            android:textColor="#000"
            android:layout_gravity="center"/>
        <TextView
            android:id="@+id/reitem2_tv_sub"
            android:layout_marginStart="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="This is SubTitle"
            android:textSize="14sp"
            android:textColor="#888"
            android:layout_gravity="center"/>
    </LinearLayout>
</LinearLayout>
Android入门教程

那么上一期说道,一个列表项目就可以当做是一个ViewHolder,我们使用onBindViewHolder为每一个项目(ViewHolder)绑定数据,那么以此可得出,只要判断项目的显示类型并在onCreateViewHolder内返回对应的ViewHolder就好了,再将ViewHolder传给onBindViewHolder对应的ViewHolder,就可以实现多样式布局。那么下面来看看具体如何实现呢。

我们还需要再创建一个ViewHolder,名字随意,这边命名为Style2Holder,然后获取所需组件。

    class Style2Holder extends RecyclerView.ViewHolder {
        TextView textViewTitle,textViewSubTitle;
        public Style2Holder(@NonNull View itemView) {
            super(itemView);
            textViewTitle = itemView.findViewById(R.id.reitem2_tv);
            textViewSubTitle = itemView.findViewById(R.id.reitem2_tv_sub);
        }
    }

这里需要注意,上一期说道使用List给适配器传入数据,那么这里新的布局中有两个组件,想要给它们指定内容,要怎么做呢?当然,非常简单粗暴的方法,直接用特殊分割符分割数据传入,如果这样,还有更多布局又要怎么办呢。

我们可以把RecyclerView中的每一个项目都当做一个对象,这些不同对象共同继承一个父类,这个父类就是泛指所有项目。那么说得有的抽象,来具体的例子看一看吧(注意:若不能理解面向对象的朋友请自行学习):

RvItemParent.java

public class RvItemParent {
    public ItemType itemType;

    public RvItemParent(ItemType itemType) {
        this.itemType = itemType;
    }

    enum ItemType {
        Normal,
        SubTitle
    }
}

RvItemNormal.java

public class RvItemNormal extends RvItemParent {
    public String title;
    public RvItemNormal(ItemType itemType) {
        super(ItemType.Normal);
    }
}

RvItemSubTitle.java

public class RvItemSubTitle extends RvItemParent {
    public String title;
    public String subTitle;
    public RvItemSubTitle(ItemType itemType) {
        super(ItemType.SubTitle);
    }
}

上述代码中,我在父类使用了枚举,以用于判断样式类型,在SubTitle的子类中,声明了两个变量以用于绑定数据。那么现在我们只需要给适配器传入RvItemParent的数组就可以了,去改一改代码吧,回到主类中(至于怎么改…有Java基础的都知道对吧,没基础也不会直接冲Android吧…?)。

下面是改好的主类和适配器,只是将List的数据类型换了一下,然后将onBindViewHolder内的代码全部清空。

public class MainActivity extends AppCompatActivity {
    public RecyclerViewAdapter recyclerViewAdapter;
    public List<RvItemParent> rvItems = new ArrayList<>();
    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RvItemNormal normal = new RvItemNormal(null);
        normal.title = "这里是普通项目的标题";
        RvItemSubTitle subTitle = new RvItemSubTitle(null);
        subTitle.title = "这里是第二样式的标题";
        subTitle.subTitle = "这里是第二样式的子标题";
        
        rvItems.add(normal);
        rvItems.add(subTitle);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerViewAdapter = new RecyclerViewAdapter(this, rvItems);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
        recyclerView.setLayoutManager(linearLayoutManager);

        recyclerView.setAdapter(recyclerViewAdapter);
    }
}
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    public Context mContext;
    public List<RvItemParent> mDatas;

    public RecyclerViewAdapter(Context mContext, List<RvItemParent> mDatas) {
        this.mContext = mContext;
        this.mDatas = mDatas;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(mContext).inflate(R.layout.reitem, parent, false);
        return new MainViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

    }

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


    class MainViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        public MainViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.reitem_tv);
        }
    }

    class Style2Holder extends RecyclerView.ViewHolder {
        TextView textViewTitle,textViewSubTitle;
        public Style2Holder(@NonNull View itemView) {
            super(itemView);
            textViewTitle = itemView.findViewById(R.id.reitem2_tv);
            textViewSubTitle = itemView.findViewById(R.id.reitem2_tv_sub);
        }
    }
}

好,到这里就完成了第二样式的创建,下一步就是数据处理了。现在我们给适配器传入了RvItemParent数组,那么我们需要在创建每一个ViewHolder的时候判断它们的类型并返回对应的ViewHolder,那么你可能早就注意到了,在onCreateViewHolder中还有一个int viewType是干什么用的,那么下面我们就要用到它来判断显示类型。在适配器中添加一个方法getItemViewType(),如下:

@Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }

如果你是直接使用Android Studio创建的如上所示,那么我们就需要通过它的position来获取对应的父类,通过itemType枚举返回对应的viewType,下面就直接放修改好的代码吧:

    @Override
    public int getItemViewType(int position) {
        switch (mDatas.get(position).itemType) {
            case Normal:
                return 0;
            case SubTitle:
                return 1;
        }
        return 0;
    }

那么现在我们可以正常返回viewType了,回到onCreateViewHolder,当每一个ViewHolder要被创建时,适配器都会通过getItemViewType给onCreateViewHolder传入我们想要的viewType,接下来稍微改造一下它:

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(mContext).inflate(R.layout.reitem, parent, false);
        View itemView2 = LayoutInflater.from(mContext).inflate(R.layout.reitems2, parent, false);
        switch (viewType) {
            case 0:
                return new MainViewHolder(itemView);
            case 1:
                return new Style2Holder(itemView2);
        }
        return new MainViewHolder(itemView);
    }

好了,改造完成,最后一步就是绑定数据啦,来到onBindViewHolder,先获取到父类,再用instanceof判断其具体子类型,强转RecyclerView.ViewHolder。

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        RvItemParent parent = mDatas.get(position);
        if (parent instanceof RvItemNormal) {
            MainViewHolder mainViewHolder = (MainViewHolder) holder;
            // Bind Data to components
        }else if (parent instanceof RvItemSubTitle) {
            Style2Holder style2Holder = (Style2Holder) holder;
            // Bind Data to components
        }
    }

在注释的地方写上你想要的代码即可,那么到这里所有的代码已经写完了,下面就来看看效果吧,先贴上适配器所有代码:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    public Context mContext;
    public List<RvItemParent> mDatas;

    public RecyclerViewAdapter(Context mContext, List<RvItemParent> mDatas) {
        this.mContext = mContext;
        this.mDatas = mDatas;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(mContext).inflate(R.layout.reitem, parent, false);
        View itemView2 = LayoutInflater.from(mContext).inflate(R.layout.reitems2, parent, false);
        switch (viewType) {
            case 0:
                return new MainViewHolder(itemView);
            case 1:
                return new Style2Holder(itemView2);
        }
        return new MainViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        RvItemParent parent = mDatas.get(position);
        if (parent instanceof RvItemNormal) {
            MainViewHolder mainViewHolder = (MainViewHolder) holder;
            // Bind Data to components
            mainViewHolder.textView.setText(((RvItemNormal) parent).title);
        }else if (parent instanceof RvItemSubTitle) {
            Style2Holder style2Holder = (Style2Holder) holder;
            // Bind Data to components
            style2Holder.textViewTitle.setText(((RvItemSubTitle) parent).title);
            style2Holder.textViewSubTitle.setText(((RvItemSubTitle) parent).subTitle);
        }
    }

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

    @Override
    public int getItemViewType(int position) {
        switch (mDatas.get(position).itemType) {
            case Normal:
                return 0;
            case SubTitle:
                return 1;
        }
        return 0;
    }

    class MainViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        public MainViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.reitem_tv);
        }
    }

    class Style2Holder extends RecyclerView.ViewHolder {
        TextView textViewTitle,textViewSubTitle;
        public Style2Holder(@NonNull View itemView) {
            super(itemView);
            textViewTitle = itemView.findViewById(R.id.reitem2_tv);
            textViewSubTitle = itemView.findViewById(R.id.reitem2_tv_sub);
        }
    }
}

主类的代码在上面,到这里没有变更,下面看看实机测试的效果吧:

Android入门教程

运用多样式的特效,我们可以创建多种多样的布局并且在同一个RecyclerView中显示,例如目前的TapTap游戏商店、简书等APP的列表中,都有带图项目、无图项目或是广告块,这些都可以用RecyclerView来实现。

那么本期教程就到此结束啦,若你有任何问题欢迎在评论区留言,感谢观看!


0 条评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注