Brvah在RecyclerView中的使用
BRVAH在RecyclerView中的使用
前言
RecyclerView虽然好用但是确实比起ListView使用难度上略大,写过五遍以上的原始的RecyclerView.Adapter后我迫切的打开了全球最大单生交友平台GitHub,寻找BaseAdapter for RecyclerView。然后我找到了BAVAH。哈哈赶快学习一下。
BRVAH github地址:https://github.com/CymChad/BaseRecyclerViewAdapterHelper
学习目标
- 加载普通列表布局
- item点击事件,item子元素点击事件
- item设置加载动画
- 下拉刷新上拉加载
- RecyclerView添加头部和尾部
- 多类型item列表
- 恩 暂时就先这么多吧,后续有新需求再持续更新......
具体实现
先看看效果,实现凤凰新闻客户端新闻列表,包含banner头部和三张item类型的新闻列表,实现底部自动加载更多,下拉刷新。点击item能够进入新闻详情页面
image.png M2YRF_4R__5%AY3RUJ5)YOI.pngimage.png
先来看看实现这么一个复杂的列表所使用的adapter代码量有多少:
public class DocNewsAdapter extends BaseMultiItemQuickAdapter<BRVAHActivity.NewsBean, BaseViewHolder> {
private Context context;
private List<BRVAHActivity.NewsBean> list = new ArrayList<>();
public DocNewsAdapter(Context context, List<BRVAHActivity.NewsBean> list) {
super(list);
this.context = context;
this.list = list;
addItemType(BRVAHActivity.NewsBean.doc, R.layout.item_doc_news);
addItemType(BRVAHActivity.NewsBean.slide, R.layout.item_slide_news);
addItemType(BRVAHActivity.NewsBean.text_live, R.layout.item_textlive_news);
}
@Override
protected void convert(BaseViewHolder baseViewHolder, BRVAHActivity.NewsBean item) {
switch (baseViewHolder.getItemViewType()) {
case BRVAHActivity.NewsBean.doc:
baseViewHolder.setText(R.id.txt_doc_title, item.docNewsBean.getTitle())
.setText(R.id.txt_doc_commentsall, item.docNewsBean.getCommentsall())
.setText(R.id.txt_doc_source, item.docNewsBean.getSource())
.setText(R.id.txt_doc_updateTime, item.docNewsBean.getUpdateTime());
Glide.with(context).load(item.docNewsBean.getThumbnail()).placeholder(R.drawable.ic_fh_defals)
.crossFade().into((ImageView) baseViewHolder.getView(R.id.img_doc_thumbnail));
baseViewHolder.addOnClickListener(R.id.img_doc_thumbnail);
break;
case BRVAHActivity.NewsBean.slide:
baseViewHolder.setText(R.id.txt_slide_title, item.slideNewsBean.getTitle())
.setText(R.id.txt_slide_commensall, item.slideNewsBean.getCommentsall())
.setText(R.id.txt_slide_resource, item.slideNewsBean.getSource());
for (int i = 0; i < item.slideNewsBean.getStyle().getImages().size(); i++) {
if (i == 0)
Glide.with(context).load(item.slideNewsBean.getStyle().getImages().get(i)).placeholder(R.drawable.ic_fh_defals)
.crossFade().into((ImageView) baseViewHolder.getView(R.id.img_slie_img1));
else if (i == 1)
Glide.with(context).load(item.slideNewsBean.getStyle().getImages().get(i)).placeholder(R.drawable.ic_fh_defals)
.crossFade().into((ImageView) baseViewHolder.getView(R.id.img_slie_img2));
else if (i == 2)
Glide.with(context).load(item.slideNewsBean.getStyle().getImages().get(i)).placeholder(R.drawable.ic_fh_defals)
.crossFade().into((ImageView) baseViewHolder.getView(R.id.img_slie_img3));
}
break;
case BRVAHActivity.NewsBean.text_live:
baseViewHolder.setText(R.id.txt_textlive_title, item.textLiveNewsBean.getTitle());
Glide.with(context).load(item.textLiveNewsBean.getThumbnail()).placeholder(R.drawable.ic_fh_defals)
.centerCrop().into((ImageView) baseViewHolder.getView(R.id.img_textlive_thumbnail));
break;
}
}
}
完成全部功能的activity代码
public class BRVAHActivity extends AppCompatActivity implements BaseQuickAdapter.OnItemClickListener,
BaseQuickAdapter.OnItemChildClickListener, BaseQuickAdapter.RequestLoadMoreListener, SwipeRefreshLayout.OnRefreshListener {
Toolbar toolbar;
LinearLayout container;
int currentPage = 0, totalPage = 0;
boolean isRefresh = true;//当前操作是否是下拉刷新
List<NewsBean> list = new ArrayList<>();
@BindView(R.id.recyc_news)
RecyclerView recyclerView;
DocNewsAdapter adapter;
@BindView(R.id.swipeRefreshLayout)
SwipeRefreshLayout mSwipeRefreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_brvah);
ButterKnife.bind(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}
toolbar = (Toolbar) findViewById(R.id.tb_toolbar);
setSupportActionBar(toolbar);
requestData(currentPage);
adapter = new DocNewsAdapter(BRVAHActivity.this, list);
recyclerView.setLayoutManager(new LinearLayoutManager(BRVAHActivity.this));
recyclerView.setAdapter(adapter);
//item点击事件
adapter.setOnItemClickListener(this);
//item子元素点击事件
adapter.setOnItemChildClickListener(this);
// adapter.openLoadAnimation();
adapter.isFirstOnly(false);
//adapter设置头部banner
adapter.addHeaderView(initBanner());
//自动加载
adapter.setOnLoadMoreListener(this);
//上拉刷新
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeColors(Color.rgb(47, 223, 189));
}
/**
* 初始化banner
*/
private View initBanner() {
container = (LinearLayout) findViewById(R.id.container);
View customBanner = LayoutInflater.from(this).inflate(R.layout.custom_banner, container, false);
ViewGroup viewGroup = (ViewGroup) customBanner;
Banner banner = (Banner) viewGroup.getChildAt(0);
banner.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(int position) {
Toast.makeText(BRVAHActivity.this, "点击了focus news" + position, Toast.LENGTH_SHORT).show();
}
});
return customBanner;
}
/**
* 请求新闻数据
*
* @param page 第几页新闻
*/
private void requestData(final int page) {
OkHttpUtils
.get()
.url(API.getFh_toutiao() + page)
.build()
.execute(new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
Toast.makeText(BRVAHActivity.this, "网络请求失败,请检查网络设置", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(String response, int id) {
JSONObject data = (JSONObject) JSON.parseArray(response).get(0);
totalPage = data.getInteger("totalPage");
currentPage = data.getInteger("currentPage");
JSONArray item = data.getJSONArray("item");
for (int i = 0; i < item.size(); i++) {
JSONObject newsData = (JSONObject) item.get(i);
String newsType = newsData.getString("type");
if (newsType.equals("doc")) {
DocNewsBean docNewsBean = JSON.parseObject(item.get(i).toString(), DocNewsBean.class);
NewsBean newsBean = new NewsBean(NewsBean.doc, docNewsBean, null, null);
list.add(newsBean);
} else if (newsType.equals("slide")) {
SlideNewsBean slideNewsBean = JSON.parseObject(item.get(i).toString(), SlideNewsBean.class);
NewsBean newsBean = new NewsBean(NewsBean.slide, null, slideNewsBean, null);
list.add(newsBean);
} else if (newsType.equals("text_live")) {
TextLiveNewsBean textLiveNewsBean = JSON.parseObject(item.get(i).toString(), TextLiveNewsBean.class);
NewsBean newsBean = new NewsBean(NewsBean.text_live, null, null, textLiveNewsBean);
list.add(newsBean);
}
}
adapter.notifyDataSetChanged();
if (isRefresh) {
//结束下拉刷新动画
mSwipeRefreshLayout.setRefreshing(false);
} else {
//结束加载更多动画
adapter.loadMoreComplete();
}
}
});
}
/**
* item的点击事件
*
* @param adapter 设置点击事件的Adapter
* @param view item的view
* @param position item位置
*/
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
Intent intent = new Intent(BRVAHActivity.this, NewsDitailsActivity.class);
String url = null;
if (list.get(position).docNewsBean != null)
url = list.get(position).docNewsBean.getLink().getWeburl();
else if (list.get(position).slideNewsBean != null)
url = list.get(position).slideNewsBean.getLink().getWeburl();
else if (list.get(position).textLiveNewsBean != null)
url = list.get(position).textLiveNewsBean.getLink().getWeburl();
intent.putExtra("url", url);
startActivity(intent);
}
/**
* item子元素点击事件
*
* @param adapter
* @param view
* @param position
* @return
*/
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
Toast.makeText(BRVAHActivity.this, "点击子元素中的图片" + position, Toast.LENGTH_SHORT).show();
}
@Override
public void onLoadMoreRequested() {
isRefresh = false;
if (currentPage < totalPage) {
requestData(currentPage + 1);
} else {
adapter.loadMoreEnd();
}
}
/**
* 下拉刷新
*/
@Override
public void onRefresh() {
isRefresh = true;
currentPage = 0;
list.clear();
requestData(currentPage);
}
/**
* 包含三种类型的新闻实体
*/
public class NewsBean implements MultiItemEntity {
public DocNewsBean docNewsBean;
public SlideNewsBean slideNewsBean;
public TextLiveNewsBean textLiveNewsBean;
private int itemType;
public static final int doc = 1;
public static final int slide = 2;
public static final int text_live = 3;
public NewsBean(int itemType, DocNewsBean docNewsBean, SlideNewsBean slideNewsBean, TextLiveNewsBean
textLiveNewsBean) {
this.docNewsBean = docNewsBean;
this.slideNewsBean = slideNewsBean;
this.textLiveNewsBean = textLiveNewsBean;
this.itemType = itemType;
}
@Override
public int getItemType() {
return this.itemType;
}
}
}
减少了绝大部分adapter代码量,效率还是非常高的。
仿照凤凰新闻客户端头条新闻列表部分,使用RecyclerView+BRVAH实现具有banner头部的新闻列表,具有上拉刷新下拉加载,点击查看新闻详情的功能。凤凰新闻-头条新闻列表如下:
项目使用到的库如下:
dependencies {
...
compile 'com.android.support:recyclerview-v7:26.+'
compile 'cn.yipianfengye.android:zxing-library:1.1'
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
compile 'com.zhy:okhttputils:2.6.2'
compile 'net.qiujuer.genius:ui:2.0.0'
compile 'net.qiujuer.genius:res:2.0.0'
compile 'de.hdodenhof:circleimageview:2.1.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
testCompile 'junit:junit:4.12'
compile files('libs/fastjson-1.2.36.jar')
compile files('libs/glide-3.7.0.jar')
compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22'
}
1: 加载普通列表布局
现加载凤凰新闻type为doc的普通新闻数据列表
初始化Adapter,三部曲没啥好说的
adapter = new DocNewsAdapter(BRVAHActivity.this, list);
recyclerView.setLayoutManager(new LinearLayoutManager(BRVAHActivity.this));
recyclerView.setAdapter(adapter);
Adapter实现如下,传入数据绑定即可(R.layout.item_doc_news是item布局,list是新闻数据实体类)
public class DocNewsAdapter extends BaseQuickAdapter<DocNewsBean, BaseViewHolder> {
private Context context;
private List<DocNewsBean> list = new ArrayList<>();
public DocNewsAdapter(Context context, List<DocNewsBean> list) {
super(R.layout.item_doc_news,list);
this.context = context;
this.list = list;
}
@Override
protected void convert(BaseViewHolder baseViewHolder, DocNewsBean item) {
baseViewHolder.setText(R.id.txt_doc_title, item.getTitle())
.setText(R.id.txt_doc_commentsall, item.getCommentsall())
.setText(R.id.txt_doc_source, item.getSource())
.setText(R.id.txt_doc_updateTime, item.getUpdateTime());
Glide.with(context).load(item.getThumbnail()).placeholder(R.drawable.ic_fh_defals).crossFade().into((ImageView) baseViewHolder.getView(R.id.img_doc_thumbnail));
}
}
效果如如下:
123.png2:item,item子元素点击事件
activity中调用
//item点击事件
adapter.setOnItemClickListener(this);
//item子元素点击事件
adapter.setOnItemChildClickListener(this);
/**
* item的点击事件
*
* @param adapter 设置点击事件的Adapter
* @param view item的view
* @param position item位置
*/
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
Toast.makeText(BRVAHActivity.this, "点击了第" + position + "个item", Toast.LENGTH_SHORT)
.show();
}
/**
* item子元素点击事件
*
* @param adapter
* @param view
* @param position
* @return
*/
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
Toast.makeText(BRVAHActivity.this, "点击子元素中的图片" + position, Toast.LENGTH_SHORT).show();
}
子元素的点击需要再Adapter中进行绑定
/**
* 新闻列表adapter
* Created by CYQ on 2017/8/26.
*/
public class DocNewsAdapter extends BaseQuickAdapter<DocNewsBean, BaseViewHolder> {
private Context context;
private List<DocNewsBean> list = new ArrayList<>();
public DocNewsAdapter(Context context, List<DocNewsBean> list) {
super(R.layout.item_doc_news, list);
this.context = context;
this.list = list;
}
@Override
protected void convert(BaseViewHolder baseViewHolder, DocNewsBean item) {
baseViewHolder.setText(R.id.txt_doc_title, item.getTitle())
.setText(R.id.txt_doc_commentsall, item.getCommentsall())
.setText(R.id.txt_doc_source, item.getSource())
.setText(R.id.txt_doc_updateTime, item.getUpdateTime());
//为子元素中的图片设置点击事件
Glide.with(context).load(item.getThumbnail()).placeholder(R.drawable.ic_fh_defals).crossFade().into((ImageView)
baseViewHolder.getView(R.id.img_doc_thumbnail));
baseViewHolder.addOnClickListener(R.id.img_doc_thumbnail);
}
}
这么简单就实现了item和他的子元素的点击事件,比起原生的Adapter少了太多的代码了。
item设置加载动画
个人感觉为item设置动画没太大的实际用途,哈哈BRVAH为item设置动画一行代码搞定
adapter.openLoadAnimation();
BRVAH为开发者提供了五中默认的动画效果:渐显、缩放、从下到上,从左到右、从右到左通过quickAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);设置即可
下拉刷新上拉加载
下拉刷新使用Android SDK自带的SwipeRefreshLayout
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyc_news"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
//上拉刷新
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeColors(Color.rgb(47, 223, 189));
//............
/**
* 下拉刷新
*/
@Override
public void onRefresh() {
//刷新操作
}
上拉加载
BRVAH提供了自动加载更多的属性,也可以自定义加载更多的view
//上拉自动加载
adapter.setOnLoadMoreListener(this);
...
@Override
public void onLoadMoreRequested() {
//加载更多操作
}
恩就是这么方便就实现了列表上拉加载下拉刷新的功能
添加头部banner
这里我自定义了一个banner轮播View,BRVAH为RecyclerView提供了和listview一样方便的增加头部的功能addHeadView(youHeadView).
adapter.addHeaderView(initBanner());
initBanner();是我自定义的广告banner,返回一个view类型,把他替换成你要add的view就OK。
/**
* 初始化banner
*/
private View initBanner() {
container = (LinearLayout) findViewById(R.id.container);
View customBanner = LayoutInflater.from(this).inflate(R.layout.custom_banner, container, false);
ViewGroup viewGroup = (ViewGroup) customBanner;
Banner banner = (Banner) viewGroup.getChildAt(0);
banner.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(int position) {
Toast.makeText(BRVAHActivity.this, "点击了focus news" + position, Toast.LENGTH_SHORT).show();
}
});
return customBanner;
}
多类型item列表
持续更新中。。。。。