大家都知道,RecycleView默认只能通过setLayoutManager()方法指定一种布局结构,那么像支付宝首页这样复杂的多布局情况如何处理呢?在ListView中,我们也遇到过这种情况,是通过getItemViewType结合其他方法,通过判断类型来加载不同的布局。在RecycleView中也同样使用,今天我们主要介绍RecycleView多布局实现,其中布局嵌套了GridView,有些坑需要注意,避免陷入。
一、效果图
废话不多说,献上效果图。
从图中可以看出,一共有三种布局样式。第一种:头布局,包含各种类型的新闻频道。第二种布局:普通的新闻。第三种布局:多图图集新闻。
二、多布局实现的思路
步骤一、getItemViewType()方法判断不同的布局,返回判断结果。
步骤二、创建不同的ViewHolder类,针对不同的布局类型,进行对应的布局内控件的初始化。
步骤三、onCreateViewHolder()方法根据第一步的判断结果,得到viewType,根据viewType值,实例化不同类型的ViewHolder对象。
步骤四、onBindViewHolder()方法判断holder所属类型,进行相对应类型的布局内控件内容的赋值。
以上就是实现多布局的思路,很简单(可能描述不到位,不易理解),下面我们以代码的形式更直观的来了解具体步骤。
三、RecycleView多布局实现代码
首先定义三种类型常量
//新闻模式
private static final int TYPE_SINGLE = 0;
//图集模式
private static final int TYPE_MULTI = 1;
//头布局模式
private static final int TYPE_HEADER = 2;
getItemViewType()方法判断不同的布局,返回判断结果
@Override
public int getItemViewType(int position) {
//所有的新闻详情数据,在第一个位置自己手动加入了一个假的新闻数据,把它的title设置为“头布局”
NewsInfo info = list.get(position);
//识别出“头布局”,则是第一个数据,把它归于头布局类型
if(info.getTitle().endsWith("头布局")){
return TYPE_HEADER;
}
//有新闻具体内容,是普通新闻
if (!TextUtils.isEmpty(info.getDigest()))
{
return TYPE_SINGLE;
}
//其他情况,是图集新闻
return TYPE_MULTI;
}
创建不同的ViewHolder类,针对不同的布局类型,进行对应的布局内控件的初始化。
省略了具体的初始化操作
public class SingleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
.......
.......
public SingleViewHolder(View itemView) {
super(itemView);
.......
.......
}
@Override
public void onClick(View view) {
Toast.makeText(context,"点击了",Toast.LENGTH_SHORT).show();
}
}
public class MultiViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
.......
.......
public MultiViewHolder(View itemView) {
super(itemView);
.......
.......
}
@Override
public void onClick(View view) {
Toast.makeText(context,"点击了",Toast.LENGTH_SHORT).show();
}
}
public class HeaderViewHolder extends RecyclerView.ViewHolder{
.......
.......
public HeaderViewHolder(View itemView) {
super(itemView);
.......
.......
}
}
onCreateViewHolder()方法根据第一步的判断结果,得到viewType,根据viewType值,实例化不同类型的ViewHolder对象。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_SINGLE:
return new SingleViewHolder(inflater.inflate(R.layout.item_news, parent, false));
case TYPE_MULTI:
return new MultiViewHolder(inflater.inflate(R.layout.item_news_photo, parent, false));
case TYPE_HEADER:
return new HeaderViewHolder(inflater.inflate(R.layout.item_news_header,parent,false));
}
return null;
}
onBindViewHolder()方法判断holder所属类型,进行相对应类型的布局内控件内容的赋值。
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//设置不同的布局内控件的值
if (holder instanceof SingleViewHolder) {
setNormalItemValues((SingleViewHolder) holder,position);
}else if(holder instanceof MultiViewHolder){
setMultiItemValues((MultiViewHolder) holder,position);
}else{
setHeaderItemValues((HeaderViewHolder) holder);
}
}
针对不同类型,设置布局内控件的值的具体内容就不介绍了,比较繁多,下面有源码链接。
由于本例中头布局是个GridView,需要注意的一点是RecycleView中嵌套GridView会出现只显示一行的问题。下面给出具体解决方法:
在setHeaderItemValues((HeaderViewHolder) holder);
中,主动测量出GridView的高度,并设置给布局。本例中默认GridView是两行。
//解决GridView只显示一行的原因 主动设置GridView的高度
ViewGroup.LayoutParams params = holder.mGridView.getLayoutParams();
View view = mAdapter.getView(0, null, holder.mGridView);
view.measure(0,0);
int height =view.getMeasuredHeight();
int totalHeight = holder.mGridView.getVerticalSpacing() * 2 + height * 2;
params.height = totalHeight;
holder.mGridView.setLayoutParams(params);
源码地址比较乱,直接看NewsFragment相关内容即可。