网站设计的技能要求2345网址导航中国最好
这里写目录标题
- 前言:
- 一,基础使用
- 1.1 简单布局
- 1.2 横向显示
- 1.3 网格显示
- 1.4 网格显示升级版
- 二,网格布局升级版使用
- 2.1 第一部分页面
- 2.2 bean类和holder类
- 2.3 ItemHolderFactory 类
- 2.4 MultiViewAdapter 类
- 2.5 MainActivity类
- 三,封装
- 四,RecyclerView原理
前言:
开发中离不开的RecyclerView,用好它让开发UI更加丝滑。通常在使用RecyclerView的时候,我们都会用到多布局,尤其是APP的首页。像那些大厂的首页,比如:京东,淘宝,美团,QQ音乐等。都不是简单的布局,有些涉及到嵌套问题。一旦使用了嵌套,会有各种问题,性能问题,滑动问题等。因此我们在开发中尽量避免多层嵌套。
当然本篇文章没有涉及到更复杂的布局使用,像列表中存在横向滑动,分页,嵌套viewpager,嵌套tablayout等,这些使用场景有同学做过优化的可以一起讨论交流。
一,基础使用
1.1 简单布局
写一个简单布局只有TextView,简单点,写代码的方式简单点。
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.TestViewHolder> {private List<String> mList = new ArrayList<>();public TestAdapter(List<String> list) {this.mList = list;}@NonNull@Overridepublic TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_test, parent,false);return new TestViewHolder(view);}@Overridepublic void onBindViewHolder(@NonNull TestViewHolder holder, int position) {holder.textView.setText(mList.get(position));}@Overridepublic int getItemCount() {return mList.size();}class TestViewHolder extends RecyclerView.ViewHolder {private AppCompatTextView textView;public TestViewHolder(@NonNull View itemView) {super(itemView);textView = itemView.findViewById(R.id.item_tv);}}}
mRecyclerView=findViewById(R.id.activity_rv);mRecyclerView.setLayoutManager(new LinearLayoutManager(this));List<String> list=new ArrayList<>();list.add("学生");list.add("老师");list.add("家长");list.add("同事");TestAdapter testAdapter=new TestAdapter(list);mRecyclerView.setAdapter(testAdapter);
代码很简单,但是需要注意的是一下两种布局加载方式。如果用了第二种,你会发现无法居中显示。
View view = LayoutInflater.from(context).inflate(R.layout.item_test, parent,false);View view1=LayoutInflater.from(context).inflate(R.layout.item_test,null);
1.2 横向显示
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,RecyclerView.HORIZONTAL,false));
1.3 网格显示
mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
1.4 网格显示升级版
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4);gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {// 显示的列数 = spanCount / spanSize ;if (position % 5 == 4) {//SpanSize 返回4 代表该行只显示1列 列数 = 4/4 =1return 4;} else {//SpanSize 返回1代表该行显示4列 列数 = 4/1 =4return 1;}}});
二,网格布局升级版使用
如果要实现上图的效果,我们该如何去设计呢。首先需要分析上图一共有几种布局,再者由于是一维布局,我们可以采用非嵌套模式去实现。当然这里如果支持二维布局的横向滑动呀,分页滑动呀等,这种就得需要使用嵌套了,我们先不说嵌套。就是利用上文中介绍的setSpanSizeLookup方式去实现。
开始分析:上图布局种类,一共可以看成4中,当然第一个位置一般都是banner轮番图,在这里我们可以看成是一张图片。这四种布局显示类型分别是,1,2,4,5,也就是一行显示几个。我们知道在网格布局中,我们需要指定一行显示几个,比如:GridLayoutManager(this, 4),这里的4代表一行显示4个,但是我们要用setSpanSizeLookup方式去显示,怎么去计算呢,这里我找到了一个通用的做法。
通用方式:基数代表GridLayoutManager(this, 4)传入的值,这里是4
比如:基数4,可以显示几种布局呢,1,2,4
比如:基数5,可以显示几种布局呢,1,5
比如:基数6,可以显示几种布局呢,1,2,3,6
有没有发现规律,能显示几种布局,就看哪些数可以被基数整除了。
因此要实现上文中的1,2,4,5类型的布局,那就要找到被他们整除的数。当然这里是20了。
这里有同学就会问了,为什么是整数倍呢,因为上文getSpanSize方法返回的是整数。假如布局中有显示1,2,3,4,5的该怎么办呢,这种方式就不行了。
好了,我们开始写代码吧,实现上图效果。
2.1 第一部分页面
item_banner.xml内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid:layout_width="match_parent"android:layout_height="80dp"android:background="#78D2DD" />
</LinearLayout>
item_icon.xml内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><ImageViewandroid:layout_marginTop="10dp"android:layout_marginBottom="10dp"android:layout_width="60dp"android:layout_height="60dp"android:background="#B66666" />
</LinearLayout>
item_title.xml内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:textColor="#000000"android:text="分类"android:textSize="24sp" />
</LinearLayout>
item_content1.xml内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><ImageViewandroid:layout_width="160dp"android:layout_height="60dp"android:layout_marginBottom="10dp"android:background="#F33737" />
</LinearLayout>
item_content2.xml内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:gravity="center"android:layout_height="wrap_content"><ImageViewandroid:layout_width="80dp"android:layout_height="80dp"android:background="#CAC27B" />
</LinearLayout>
2.2 bean类和holder类
BaseItem类
public interface BaseItem {int getType();
}
BannerItem类
public class BannerItem implements BaseItem {@Overridepublic int getType() {return ItemHolderFactory.BANNER_TYPE;}
}
…更多省略
BaseHolder类
public abstract class BaseHolder extends RecyclerView.ViewHolder {BaseHolder(View item) {super(item);}
}
BannerHolder 类
public class BannerHolder extends BaseHolder {public BannerHolder(View item) {super(item);}
}
…更多省略
2.3 ItemHolderFactory 类
public class ItemHolderFactory {public static final int BANNER_TYPE = 0;public static final int TITLE_TYPE = 1;public static final int ICON_TYPE = 2;public static final int CONTENT1_TYPE = 4;public static final int CONTENT2_TYPE = 5;public static BaseHolder getItemHolder(ViewGroup parent, int type) {switch (type) {default:case BANNER_TYPE:return new BannerHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_banner, parent, false));case TITLE_TYPE:return new TitleHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_title, parent, false));case ICON_TYPE:return new IconHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_icon, parent, false));case CONTENT1_TYPE:return new ContentHolder1(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_content1, parent, false));case CONTENT2_TYPE:return new ContentHolder2(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_content2, parent, false));}}
}
2.4 MultiViewAdapter 类
public class MultiViewAdapter extends RecyclerView.Adapter<BaseHolder> {private List<BaseItem> mDataList;public MultiViewAdapter(List<BaseItem> dataList) {mDataList = dataList;}@NonNull@Overridepublic BaseHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) {return ItemHolderFactory.getItemHolder(viewGroup, type);}@Overridepublic void onBindViewHolder(@NonNull BaseHolder viewHolder, int i) {}@Overridepublic int getItemViewType(int position) {//Get the type of itemreturn mDataList.get(position).getType();}@Overridepublic int getItemCount() {return mDataList.size();}public void setSpanCount(GridLayoutManager layoutManager) {layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {@Overridepublic int getSpanSize(int i) {int type = getItemViewType(i);switch (type) {default:case ItemHolderFactory.BANNER_TYPE:case ItemHolderFactory.TITLE_TYPE:return 20;//一行显示1个item 20/20=1case ItemHolderFactory.ICON_TYPE:return 4;//一行显示5个item 20/4=5case ItemHolderFactory.CONTENT1_TYPE:return 10;//一行显示2个item 20/10=2case ItemHolderFactory.CONTENT2_TYPE:return 5;//一行显示4个item 20/5=4}}});}
}
2.5 MainActivity类
对于数据这一块,同学们需要理解一下,不要弄混。记着咱们的布局是一维的,也就是相当于只有一级分类。分类title和分类子内容是同级的,所以当我们传入一个title数据的时候,对应的就要传入要显示几个子内容。
List<BaseItem> list = new ArrayList<>();//banner数据list.add(new BannerItem());//icon数据for (int i = 0; i < 10; i++) {list.add(new IconItem());}//content1数据list.add(new ContentItem1());list.add(new ContentItem1());//titlelist.add(new TitleItem());//content2for (int i=0;i<4;i++){list.add(new ContentItem2());}//titlelist.add(new TitleItem());//content1for (int i=0;i<4;i++){list.add(new ContentItem1());}GridLayoutManager layoutManager = new GridLayoutManager(this, 20);MultiViewAdapter adapter = new MultiViewAdapter(list);adapter.setSpanCount(layoutManager);recyclerView.setLayoutManager(layoutManager);recyclerView.setAdapter(adapter);
最后的最后,我们看看效果图图
三,封装
一个项目中,对于多布局的使用场景不止一处。这里有个封装的很好的库,我们可以使用一下了。
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.2'
先来看一下实体类QuickMultipleEntity
public class QuickMultipleEntity implements MultiItemEntity {public static final int BANNER_TYPE = 0;public static final int TITLE_TYPE = 1;public static final int ICON_TYPE = 2;public static final int CONTENT1_TYPE = 4;public static final int CONTENT2_TYPE = 5;private int itemType;private int spanSize;public QuickMultipleEntity(int itemType, int spanSize) {this.itemType = itemType;this.spanSize = spanSize;}public int getSpanSize() {return spanSize;}public void setSpanSize(int spanSize) {this.spanSize = spanSize;}@Overridepublic int getItemType() {return itemType;}
}
再来看看adapter
public class MultiTypeAdapter extends BaseMultiItemQuickAdapter<QuickMultipleEntity, BaseViewHolder> {public MultiTypeAdapter(List<QuickMultipleEntity> data) {super(data);addItemType(QuickMultipleEntity.BANNER_TYPE, R.layout.item_banner);addItemType(QuickMultipleEntity.TITLE_TYPE, R.layout.item_title);addItemType(QuickMultipleEntity.ICON_TYPE, R.layout.item_icon);addItemType(QuickMultipleEntity.CONTENT1_TYPE, R.layout.item_content1);addItemType(QuickMultipleEntity.CONTENT2_TYPE, R.layout.item_content2);}@Overrideprotected void convert(BaseViewHolder baseViewHolder, QuickMultipleEntity quickMultipleEntity) {switch (baseViewHolder.getItemViewType()) {case QuickMultipleEntity.BANNER_TYPE:Log.e("MultiTypeAdapter", "convert: banner");break;case QuickMultipleEntity.TITLE_TYPE:Log.e("MultiTypeAdapter", "convert: title");break;default:break;}}
}
接下来就是数据源了
public class MainActivity extends AppCompatActivity {private RecyclerView mRecyclerView;private MultiTypeAdapter multipleItemAdapter;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);supportRequestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);mRecyclerView = findViewById(R.id.activity_main_rv);List<QuickMultipleEntity> data = getMultipleItemData();multipleItemAdapter = new MultiTypeAdapter(data);final GridLayoutManager manager = new GridLayoutManager(this, 20);mRecyclerView.setLayoutManager(manager);multipleItemAdapter.setGridSpanSizeLookup(new GridSpanSizeLookup() {@Overridepublic int getSpanSize(GridLayoutManager gridLayoutManager, int viewType, int position) {return data.get(position).getSpanSize();}});mRecyclerView.setAdapter(multipleItemAdapter);}public static List<QuickMultipleEntity> getMultipleItemData() {List<QuickMultipleEntity> list = new ArrayList<>();//bannerlist.add(new QuickMultipleEntity(QuickMultipleEntity.BANNER_TYPE, 20));//iconfor (int i = 0; i < 10; i++) {list.add(new QuickMultipleEntity(QuickMultipleEntity.ICON_TYPE, 4));}//content1for (int i = 0; i < 2; i++) {list.add(new QuickMultipleEntity(QuickMultipleEntity.CONTENT1_TYPE, 10));}//titlelist.add(new QuickMultipleEntity(QuickMultipleEntity.TITLE_TYPE, 20));//content2for (int i = 0; i < 4; i++) {list.add(new QuickMultipleEntity(QuickMultipleEntity.CONTENT2_TYPE, 5));}//titlelist.add(new QuickMultipleEntity(QuickMultipleEntity.TITLE_TYPE, 20));//content1for (int i = 0; i < 4; i++) {list.add(new QuickMultipleEntity(QuickMultipleEntity.CONTENT1_TYPE, 10));}return list;}}
实现效果和上图是一样的。
四,RecyclerView原理
https://blog.csdn.net/qq_29882585/article/details/108818849
https://juejin.cn/post/6844903661726859271
https://juejin.cn/post/6984974879296585764