飞哥语录:男人还是现实点好,眼光放长远,少说话,多做事,要努力赚钱,腰包硬了,说话才硬气。
1.RecyclerView概述&简介
简单介绍:
整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。
你想要控制其显示的方式,请通过布局管理器LayoutManager
你想要控制Item间的间隔(可绘制),请通过ItemDecoration
你想要控制Item增删的动画,请通过ItemAnimator
你想要控制点击、长按事件,请自己写(擦,这点尼玛。)
给Recycler的Item的布局去设置margin,当然了这种方式不够优雅,我们文章开始说了,我们可以自由的去定制它,当然我们的分割线也是可以定制的。
ItemDecoration
我们可以通过该方法添加分割线:
mRecyclerView.addItemDecoration()
该方法的参数为RecyclerView.ItemDecoration
,该类为抽象类,官方目前并没有提供默认的实现类(我觉得最好能提供几个)
提示:如果布局管理器里面设置的Horizontal就是行,如果是Vertical就是显示几列。
2.实现步骤:
布局,适配器,继承于RecyclerView
的适配器,
viewHolder继承于RecyclerView的适配器
设置泛型,然后再次实现对应的方法
3.RecyclerView各个布局管理器的说明
1).线性布局管理器:
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
参数一:上下文; 参数二:指明线性布局的方向,参数三:是否为倒序排列;
2).网格布局管理器:
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false));
参数一:上下文; 参数二:指明行数(Horizontal),或列数(Vertical);
参数三:指明方向;参数四:是否倒序;
3).瀑布流布局管理器
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL));
参数一:指明行数(Horizontal),或列数(Vertical);
参数二:指明方向;
4.给RecyclerView的Item设置点击事件有两种:
方式一:在Adapter的onBindViewHolder()方法中设置,也可以定义一个接口回调,让MainAcitivity实现自定义的接口,然后在MainActivity设置接口回调的监听即可:mRvAdapter.setonItemClickListener();
5.一般的RecyclerView
5.1布局
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
5.2初始化控件,设置布局管理器(3种)
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
// 设置线性布局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(this));
5.3设置适配器
recyclerView.setAdapter(new MyAdapter());
5.4创建适配器
写一个类继承于Recyclerview的Adapter重写几个方法,写一个viewHolder,然后设置Adapter的泛型为当前的ViewHolder,如果有不一样的就要重写其方法
关于其几个方法的说明:
class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 创建一个ViewHolder,加载一个视图
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(AddHeadRecyclerViewActivity.this).inflate(R.layout.item, parent, false);
return new ViewHolder(view);
}
// 绑定ViewHolder,一般进行数据的绑定操作
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
// 返回有多少条Item
@Override
public int getItemCount() {
return 9;
}
// ViewHolder
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
}
5.5在onCreateViewHolde中,创建一个ViewHolder(),一般为加载一个布局文件,注意此处inflate和LayoutInflater的区别
6.分类型的RecyclerView
6.1重写方法和和一般的类似,多了一个getItemViewType()方法下面是分类的代码示例及解释
public class HomeRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final String GOODS_BEAN = "goods_bean";
/**
* 上下文
*/
private Context mContext;
/**
* 数据Bean对象
*/
private ResultBean resultBean;
/**
* 五种类型
*/
/**
* 横幅广告
*/
public static final int BANNER = 0;
/**
* 频道
*/
public static final int CHANNEL = 1;
/**
* 活动
*/
public static final int ACT = 2;
/**
* 秒杀
*/
public static final int SECKILL = 3;
/**
* 推荐
*/
public static final int RECOMMEND = 4;
/**
* 热卖
*/
public static final int HOT = 5;
/**
* 当前类型
*/
public int currentType = BANNER;
private final LayoutInflater mLayoutInflater;
public HomeRecycleAdapter(Context mContext, ResultBean resultBean) {
this.mContext = mContext;
this.resultBean = resultBean;
mLayoutInflater = LayoutInflater.from(mContext);
}
/**
* 根据位置得到类型-系统调用
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
switch (position) {
case BANNER:
currentType = BANNER;
break;
case CHANNEL:
currentType = CHANNEL;
break;
case ACT:
currentType = ACT;
break;
case SECKILL:
currentType = SECKILL;
break;
case RECOMMEND:
currentType = RECOMMEND;
break;
case HOT:
currentType = HOT;
break;
}
return currentType;
}
/**
* 返回总条数,共六种类型
* @return
*/
@Override
public int getItemCount() {
return 6;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == BANNER) {
return new BannerViewHolder(mLayoutInflater.inflate(R.layout.banner_viewpager, null), mContext, resultBean);
} else if (viewType == CHANNEL) {
return new ChannelViewHolder(mLayoutInflater.inflate(R.layout.channel_item, null), mContext);
} else if (viewType == ACT) {
return new ActViewHolder(mLayoutInflater.inflate(R.layout.act_item, null), mContext);
} else if (viewType == SECKILL) {
return new SeckillViewHolder(mLayoutInflater.inflate(R.layout.seckill_item, null), mContext);
} else if (viewType == RECOMMEND) {
return new RecommendViewHolder(mLayoutInflater.inflate(R.layout.recommend_item, null), mContext);
} else if (viewType == HOT) {
return new HotViewHolder(mLayoutInflater.inflate(R.layout.hot_item, null), mContext);
}
return null;
}
/**
* 绑定数据
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == BANNER) {
BannerViewHolder bannerViewHolder = (BannerViewHolder) holder;
bannerViewHolder.setData(resultBean.getBanner_info());
} else if (getItemViewType(position) == CHANNEL) {
ChannelViewHolder channelViewHolder = (ChannelViewHolder) holder;
channelViewHolder.setData(resultBean.getChannel_info());
} else if (getItemViewType(position) == ACT) {
ActViewHolder actViewHolder = (ActViewHolder) holder;
actViewHolder.setData(resultBean.getAct_info());
} else if (getItemViewType(position) == SECKILL) {
SeckillViewHolder seckillViewHolder = (SeckillViewHolder) holder;
seckillViewHolder.setData(resultBean.getSeckill_info());
} else if (getItemViewType(position) == RECOMMEND) {
RecommendViewHolder recommendViewHolder = (RecommendViewHolder) holder;
recommendViewHolder.setData(resultBean.getRecommend_info());
} else if (getItemViewType(position) == HOT) {
HotViewHolder hotViewHolder = (HotViewHolder) holder;
hotViewHolder.setData(resultBean.getHot_info());
}
}
class HotViewHolder extends RecyclerView.ViewHolder {
private TextView tv_more_hot;
private GridView gv_hot;
private Context mContext;
public HotViewHolder(View itemView, Context mContext) {
super(itemView);
tv_more_hot = (TextView) itemView.findViewById(R.id.tv_more_hot);
gv_hot = (GridView) itemView.findViewById(R.id.gv_hot);
this.mContext = mContext;
}
public void setData(final List<ResultBean.HotInfoBean> data) {
HotGridViewAdapter adapter = new HotGridViewAdapter(mContext, data);
gv_hot.setAdapter(adapter);
//点击事件
gv_hot.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Toast.makeText(mContext, "position:" + position, Toast.LENGTH_SHORT).show();
String cover_price = data.get(position).getCover_price();
String name = data.get(position).getName();
String figure = data.get(position).getFigure();
String product_id = data.get(position).getProduct_id();
GoodsBean goodsBean = new GoodsBean(name, cover_price, figure, product_id);
Intent intent = new Intent(mContext, GoodsInfoActivity.class);
intent.putExtra(GOODS_BEAN, goodsBean);
mContext.startActivity(intent);
}
});
}
}
6.2一般将分类型的每种类型都声明为一个常量,然后根据常量来创建对应的ViewHolder(加载自己对应的布局文件),然后在根据类型绑定自己的对应的数据;所以每一中类型都要对应自己的ViewHolder,进而实现分类型;一般还有实现其有参构造为了传递和初始化相关数据;
7.RecyclerView三种布局管理添加头的方式:
7.1LinearLayoutManager添加头部
直接分类型就可以 第一个头部是第一种类型
7.2GridLayoutManager添加头部
代码
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
GridLayoutManager manager = new GridLayoutManager(this,2);
// 重点在这 需要实现这个方法
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return position == 0 ? 2 : 1;
});
rv.setLayoutManager(manager);
rv.setAdapter(new MyAdapter());
//解释:明明头部返回的是2 怎么会是这个效果呢?返回2不应该是2列返回1是1列吗?
position 就是我们的item位置
getSpanSize返回的值就是我们的跨列度
GridLayoutManager manager = new GridLayoutManager(this,2);
大家看这个方法里的第二个参数,我们是不是指定了2列
而我们的头是不是返回了2然后显示了一行,没错,就是所占的列数。也就是我们的头占了2列 第二个item往后只占一列也就是一个item占屏幕的一半。
###7.3StaggeredGridLayoutManager添加头部
在adapter中重写些方法
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
if(lp != null
&& lp instanceof StaggeredGridLayoutManager.LayoutParams) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
//设置全屏
p.setFullSpan(holder.getLayoutPosition() == 0);
}
}
onViewAttachedToWindow()
当列表项出现到可视界面的时候调用
8.inflate&LayoutInflater
其实View.inflate的底层就是 LayoutInflate.form()
View.inflate
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
inflate(int resource, ViewGroup root, boolean attachToRoot)
1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。
2. 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。
今天给大家简单的介绍了一下RecyclerView的一般用法和分类的用法,一般我们开发使用最多的也就是这两种了,希望对大家能有所帮助。
Thanks all.