概述
在Android開發過程中,我們經常會用到adapter。因為adapter在基本使用的過程中,代碼比較繁瑣,于是進行一個簡單封裝,使調用起來更加簡單便捷。這節就來講講這個適配器的封裝吧。
前言
在Android開發過程中,我們經常會用到adapter。因為adapter在基本使用的過程中,代碼比較繁瑣,于是進行一個簡單封裝,使調用起來更加簡單便捷。這節就來講講這個適配器的封裝吧。
今天涉及的內容:
- adapter庫依賴
- 封裝類ComAdapter和GroupAdapter概述
- 通用適配器ComAdapter的使用
- 分組適配器GroupAdapter的使用
- MainActivity中調用示例
- 效果圖和項目結構圖
先來波adapter使用的效果圖吧
一. adapter庫依賴
Github地址
本adapter的封裝是建立在一個第三方庫的基礎之上的。在使用之前,你需要添加該庫的依賴:
將JitPack存儲庫添加到您的構建文件中(項目根目錄下build.gradle文件):
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
添加依賴項以最新版本為準:
dependencies {
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34'
}
二.封裝類ComAdapter和GroupAdapter概述
適配器庫BaseRecyclerViewAdapterHelper是一個專注adapter的庫,里面有一個適配器基類:BaseQuickAdapter,為了方便日常調度使用,我在BaseQuickAdapter基礎上再度擴展,分別整合了兩個adapter基類:ComAdapter和GroupAdapter。
ComAdapter:基于一般的列表或九宮格布局的使用
GroupAdapter:基于簡單的分組列表展示使用。
三.通用適配器ComAdapter的使用
ComAdapter是一個通用適配器基類,里面集成了adapter創建需要的一些基本方法,包括控件初始化,獲取布局對象,加載動畫,列表數據加載,控件點擊事件監聽等方法。 當你要實現一個線性列表,需要創建adapter的時候,繼承ComAdapter可以幫你快速實現自己的adapter。
3.1 繼承ComAdapter,寫自己的Adapter
當RecyclerView加載列表的時候,需要一個適配器(NameAdapter),你可以像這樣快速來創建它:
public class NameAdapter<T>extends ComAdapter {
private TextView mTvName;
public NameAdapter(List<T> data, Context context) {
//加載布局和數據
super(R.layout.item_layout, data, context);
}
@Override
public <T>void initView(BaseViewHolder viewHolder, T obj) {
//控件初始化
mTvName=viewHolder.getView(R.id.tv);
}
@Override
public <T>void initData(BaseViewHolder viewHolder, T obj) {
String name=obj.toString();
mTvName.setText(name);
}
@Override
public <T>void setListener(BaseViewHolder viewHolder, T obj) {
//添加控件監聽
addOnClickListener(mTvName,viewHolder,obj);
}
}
3.2 線性布局調用
mNames=new ArrayList<>();
//for (int i = 0; i < 10; i++) {
// mNames.add("小黃"+i);
//}
mNameAdapter=new NameAdapter<>(mNames,MainActivity.this);
mNameAdapter.setRecyclerLinearManager(mRecyclerView);
3.3 九宮格布局調用
mNames=new ArrayList<>();
//for (int i = 0; i < 10; i++) {
// mNames.add("小黃"+i);
//}
mNameAdapter=new NameAdapter<>(mNames,MainActivity.this);
mNameAdapter.setRecyclerGridManager(mRecyclerView,4);
3.4 設置分割線,返回RecyclerView.ItemDecoration對象
//設置線性布局分割線
LinearDividerItemDecoration linearDivider=mNameAdapter.setLinearLayoutItemSpace(mRecyclerView,5,R.color.colorAccent);
//設置九宮格局分割線
GridDividerItemDecoration gridDivider=mNameAdapter.setGridLayoutItemSpace(mRecyclerView,5,R.color.colorAccent);
3.5 移除分割線
/**移除RecycleView間距**/
removeItemSpace(RecyclerView recyclerView, RecyclerView.ItemDecoration divider)
3.6 點擊事件
//點擊事件
mNameAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
@Override
public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
switch (view.getId()) {
case R.id.tv:
ToastUtil.shortShow("====1====="+obj.toString());
break;
default:
break;
}
}
});
四. 分組適配器GroupAdapter的使用
GroupAdapter是一個列表分組顯示的適配器基類,里面集成了adapter創建需要的一些基本方法,包括控件初始化,獲取布局對象,加載動畫,列表數據加載,控件點擊事件監聽等方法。 當你要船創建一個分組顯示功能的adapter,繼承GroupAdapter可方便快捷實現
4.1 javaBean繼承SectionEntity類
GroupAdapter顯示的數據,都需要用javaBean進行封裝。并且JavaBean需要繼承SectionEntity類,然后重寫含(boolean isHeader, String header)參數的構造方法。 以Person對象為例,你需要這樣處理:
public class Person extends SectionEntity {
private String name;
private int age;
public Person(boolean isHeader, String header) {
super(isHeader,header);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.2 繼承GroupAdapter,寫自己的adapter
然后寫一個自己的adapter,繼承自GroupAdapter,以PersonAdapter為例:
public class PersonAdapter<T> extends GroupAdapter {
//header
private TextView mTvHeader;
//item
private TextView mTvItem;
public PersonAdapter(List<T> data, Context context) {
super(R.layout.item_layout, R.layout.header_layout, data,context);
}
@Override
protected void convertHead(BaseViewHolder viewHolder, SectionEntity item) {
//標題相關所有都在此處理
//標題初始化
mTvHeader=viewHolder.getView(R.id.tv_title);
//標題數據處理
mTvHeader.setText(item.header);
//標題點擊事件
addOnClickListener(mTvHeader,viewHolder,item);
}
@Override
public <T>void initView(BaseViewHolder viewHolder, T obj) {
//item初始化
mTvItem=viewHolder.getView(R.id.tv);
}
@Override
public <T>void initData(BaseViewHolder viewHolder, T obj) {
//item數據處理
Person person= (Person) obj;
mTvItem.setText("姓名:"+person.getName()+" 年齡:"+person.getAge());
}
@Override
public <T>void setListener(BaseViewHolder viewHolder, T obj) {
//item中控件監聽
addOnClickListener(mTvItem,viewHolder,obj);
}
}
其中PersonAdapter(List data, Context context)構造方法的super方法中,要引入兩個布局id,一個是item的一個是header的。 Header相關方法都在convertHead中處理。item的相關處理在initView,initData和setListener方法中進行。
4.3 線性布局使用
mPersonList=new ArrayList<>();
//for (int i = 0; i < 10; i++) {
//Person person;
//if(i%7==0){//header
// person=new Person(true,"標題"+i);
//}else{//item
// person=new Person(false,null);
// person.setName("小黑"+i);
// person.setAge(25+i);
// }
// mPersonList.add(person);
//}
mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
mPersonAdapter.setRecyclerLinearManager(mRecyclerView);
4.4 九宮格布局使用
mPersonList=new ArrayList<>();
//for (int i = 0; i < 10; i++) {
//Person person;
//if(i%7==0){//header
// person=new Person(true,"標題"+i);
//}else{//item
// person=new Person(false,null);
// person.setName("小黑"+i);
// person.setAge(25+i);
// }
// mPersonList.add(person);
//}
mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
mPersonAdapter.setRecyclerGridManager(mRecyclerView,3);
4.5 設置分割線,返回RecyclerView.ItemDecoration對象
線性布局的時候,可以像下面這樣設置分割線:
//線性布局分割線
LinearDividerItemDecoration linearDivider=mPersonAdapter.setLinearLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
注意: 在實現分組適配器<即繼承GroupAdapter的adapter>不能使用setGridLayoutItemSpace給列表設置分割線,會出現ui上顯示的bug,為了避免 用戶使用不當,我已經將GroupAdapter類中的setGridLayoutItemSpace拋出異常并做以錯誤提示。大家若還是需要在分組九宮格布局中做分割線的話, 需要自己在布局中,或者在adapter中處理數據的時候,用代碼來實現分割線效果。
4.6 移除分割線
/**移除RecycleView間距**/
removeItemSpace(RecyclerView recyclerView, RecyclerView.ItemDecoration divider)
4.7 點擊事件
若要設置adapter的點擊事件,你可以像下面這樣寫:
//點擊事件
mPersonAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
@Override
public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
Person person= (Person) obj;
switch (view.getId()) {
case R.id.tv_title://header
ToastUtil.shortShow("===="+person.header+"===");
break;
case R.id.tv://item
ToastUtil.shortShow("===="+person.getName()+"===");
break;
default:
break;
}
}
});
五.MainActivity中調用示例
下面貼出adapter在MainActivity中使用的代碼:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mBtn1;
private Button mBtn2;
private Button mBtn3;
private Button mBtn4;
private RecyclerView mRecyclerView;
private List<String>mNames;
private NameAdapter<String>mNameAdapter;
private List<Person>mPersonList;
private PersonAdapter<Person>mPersonAdapter;
private LinearDividerItemDecoration mLinearDivider;
private GridDividerItemDecoration mGridDivider;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
setListener();
}
private void initData() {
mBtn1 = findViewById(R.id.btn1);
mBtn2 = findViewById(R.id.btn2);
mBtn3 = findViewById(R.id.btn3);
mBtn4 = findViewById(R.id.btn4);
mRecyclerView = findViewById(R.id.rv);
mBtn1.setText("通用線性");
mBtn2.setText("通用九宮");
mBtn3.setText("分組線性");
mBtn4.setText("分組九宮");
}
private void setListener() {
mBtn1.setOnClickListener(this);
mBtn2.setOnClickListener(this);
mBtn3.setOnClickListener(this);
mBtn4.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1://通用布局線性測試
commonLinearLayout();
break;
case R.id.btn2://通用布局九宮格測試
commonGridLayout();
break;
case R.id.btn3://分組布局線性測試
diffGropLinearLayout();
break;
case R.id.btn4://分組布局九宮格測試
diffGropGridLayout();
break;
default:
break;
}
//點擊事件
commonDiffClick();
}
private void initCommonData(){
//通用布局
if(mNames==null) {
mNames = new ArrayList<>();
}
mNames.clear();
for (int i = 0; i < 10; i++) {
mNames.add("小黃" + i);
}
}
private void initdiffGropData(){
//分組布局
if(mPersonList==null) {
mPersonList = new ArrayList<>();
}
mPersonList.clear();
for (int i = 0; i < 10; i++) {
Person person;
if(i%7==0){//header
person=new Person(true,"標題"+i);
}else{//item
person=new Person(false,null);
person.setName("小黑"+i);
person.setAge(25+i);
}
mPersonList.add(person);
}
}
/**
* 通用布局線性測試
**/
private void commonLinearLayout() {
initCommonData();
mNameAdapter = new NameAdapter<>(mNames, MainActivity.this);
mNameAdapter.setRecyclerLinearManager(mRecyclerView);
//清除舊的分割線
mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
//設置分割線
mLinearDivider=mNameAdapter.setLinearLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
}
/**
* 通用布局九宮格測試
**/
private void commonGridLayout() {
initCommonData();
mNameAdapter = new NameAdapter<>(mNames, MainActivity.this);
mNameAdapter.setRecyclerGridManager(mRecyclerView, 3);
//清除舊的分割線
mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
//設置分割線
mGridDivider=mNameAdapter.setGridLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
}
/**
* 分組布局線性測試
**/
private void diffGropLinearLayout() {
initdiffGropData();
mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
mPersonAdapter.setRecyclerLinearManager(mRecyclerView);
//清除舊的分割線
mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
//設置分割線
mLinearDivider=mPersonAdapter.setLinearLayoutItemSpace(mRecyclerView, 5, R.color.colorAccent);
}
/**
* 分組布局九宮格測試
**/
private void diffGropGridLayout() {
initdiffGropData();
mPersonAdapter=new PersonAdapter<>(mPersonList,MainActivity.this);
mPersonAdapter.setRecyclerGridManager(mRecyclerView,3);
//清除舊的分割線
mNameAdapter.removeItemSpace(mRecyclerView,mLinearDivider);
mNameAdapter.removeItemSpace(mRecyclerView,mGridDivider);
}
/**點擊事件**/
private void commonDiffClick(){
//通用布局點擊事件
if(mNameAdapter!=null) {
mNameAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
@Override
public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
switch (view.getId()) {
case R.id.tv:
ToastUtil.shortShow("====1=====" + obj.toString());
break;
default:
break;
}
}
});
}
//分組布局點擊事件
if(mPersonAdapter!=null) {
mPersonAdapter.setOnItemClickListener(new AdapterHelper.OnItemClickListener() {
@Override
public void itemClickListener(View view, BaseViewHolder viewHolder, Object obj) {
Person person = (Person) obj;
switch (view.getId()) {
case R.id.tv_title://header
ToastUtil.shortShow("====" + person.header + "===");
break;
case R.id.tv://item
ToastUtil.shortShow("====" + person.getName() + "===");
break;
default:
break;
}
}
});
}
}
}
六. 效果圖和項目結構圖
效果圖
項目結構圖
最后
雖然萬能適配器方便好用,但是我還是推薦使用原生寫法,因為原生寫法更靈活,不會出現莫名的問題。萬能適配器的動畫目前可能有點毛病,謹慎使用列表動畫!