Day7:Recyclerview
Recyclerview
RecyclerView比ListView的优势:
1.RecyclerView比listview实现效果更多
2.RecycelrView支持多布局;
3.RecyclerView根据项目需要插拔功能
RecyclerView默认不支持点击事件->程序员代码中通过回调接口的方式添加监听
一.效果:线性/网格/瀑布流
二.重要的方法
1.RecyclerView横向滑动:
LinearLayoutManager.HORIZONTAL横向滑动LinearLayoutManager.VERTICAL垂直滑动
2.RecyclerView.Adapter中刷新方法区别:
notifyDataSetChanged();整体刷新+没有动画效果
notifyItemInserted(int position,Object data):有动画效果+添加一条数据在position位置
notifyItemRemoved(position);有动画效果+删除一条数据并刷新
注意:当添加和删除的时候,要更新下标,不然有错位现象
3.RecyclerView多布局展示:
public int getItemViewType(int position)返回当前数据的itemview类型
4.RecyclerView常见方法:
LinearLayoutManager:recyclerview线性管理器(垂直水平方向);
GridLayoutManager:网格布局管理器;
StaggeredGridLayoutManager:瀑布流布局管理器;
RecyclerView.setLayoutManager(LayoutManager manager):添加布局管理器
RecyclerView.addItemDecoration(ItemDecoration decoration):添加分割线
RecyclerView.setItemAnimator(ItemAnimator animator):添加动画方法
RecyclerView.setAdapter(Adapter adapter):添加适配器
三.RecyclerView的使用
1.gradle中导入Recyclerview引用;
implementation 'com.android.support:recyclerview-v7:28.0.0‘自己搜索导入
2.适配器:
(1)RecyclerView.Adapter<范型> 重写3个方法
onCreateViewHolder:创建ViewHolder
onBindViewHolder:绑定数据
getItemCount
(2)RecyclerView.ViewHolder
四.代码
(1)布局activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_RV"/>
</LinearLayout>
行布局:centerCrop 填充不拉伸图片 layout_margin设置内边距
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--centerCrop 填充不拉伸图片 layout_margin设置内边距 -->
<ImageView
android:layout_margin="10dp"
android:scaleType="centerCrop"
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
(2)Java代码:MainActivity.java
public class MainActivity extends AppCompatActivity implements MainAdapter.MainItemClickLisener{
private RecyclerView rv;//控件
private ArrayList<Student> list=new ArrayList<>();//数据源
private MainAdapter mainAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rv=findViewById(R.id.rv);
list.add(new Student("A",R.drawable.f1));
list.add(new Student("A",R.drawable.f2));
list.add(new Student("A",R.drawable.f3));
list.add(new Student("A",R.drawable.f4));
list.add(new Student("A",R.drawable.image1));
mainAdapter=new MainAdapter(list,this);
//TODO 1:设置布局管理器
//线性布局
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//网格布局
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
//瀑布流布局:一般和图片结合使用,自适应图片的高度
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
rv.setLayoutManager(linearLayoutManager);
//TODO 2:设置分割线
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
rv.addItemDecoration(dividerItemDecoration);
//TODO 3:设置动画
DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator();
defaultItemAnimator.setRemoveDuration(2000);//设置延迟2秒删除的效果
defaultItemAnimator.setAddDuration(2000);
rv.setItemAnimator(defaultItemAnimator);
//TODO 4:设置点击事件
mainAdapter.setOnItemClickListener(this);
rv.setAdapter(mainAdapter);
}
@Override
public void ItemClick(int position){
//删除数据
list.remove(i);
notifyItemRemoved(i);//具有动画效果+删除数据
//产生删除错位现象----->重新整理item的下表
notifyItemRangeChanged(0,list.size());//从0开始整理list集合的长度个
}
}
(3)适配器代码:MainAdapter.java
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainViewHolder> {
private ArrayList<Student> list;
private Context context;
public MainAdapter(ArrayList<Student> list, Context context) {
this.list = list;
this.context = context;
}
//TODO 3:创建ViewHolder
@NonNull
@Override
public MainViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(context).inflate(R.layout.item_main, null);
return new MainViewHolder(view);
}
//TODO 4:绑定每条数据:填充数据
@Override
public void onBindViewHolder(@NonNull MainViewHolder mainViewHolder, final int i) {
mainViewHolder.iv_pic.setImageResource(list.get(i).getPicId());
mainViewHolder.tv_name.setText(list.get(i).getName()+"");
//给item设置点击事件
mainViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Toast.makeText(context, ""+i, Toast.LENGTH_SHORT).show();
// //删除数据
// list.remove(i);
// notifyItemRemoved(i);//具有动画效果+删除数据
// //产生删除错位现象----->重新整理item的下表
// notifyItemRangeChanged(0,list.size());//从0开始整理list集合的长度个
//不要在这里做处理,采用接口回调
lisener.ItemClick(i);
}
});
}
//TODO 2:返回集合的个数
@Override
public int getItemCount() {
return list.size();
}
//TODO 1:自定义ViewHolder类
class MainViewHolder extends RecyclerView.ViewHolder{
private ImageView iv_pic;//默认值是null
private TextView tv_name;
public MainViewHolder(@NonNull View itemView) {
super(itemView);
this.iv_pic=itemView.findViewById(R.id.iv_pic);
this.tv_name=itemView.findViewById(R.id.tv_name);
}
}
//监听器
private MainItemClickLisener lisener;
//设置监听方法:将摄像头安装在31206
public void setOnItemClickListener(MainItemClickLisener listener){
this.lisener=listener;
}
//定义监听的接口:摄像头
interface MainItemClickLisener{
//一有动静就会调用该方法
public void ItemClick(int position);
}
}
五.实现多布局只给出适配器代码:微信通讯录页面
/**
- RecyclerView.ViewHolder:由于进行多布局操作
- 需要多个ViewHolder对象对应过个xml布局
- 自定义ViewHolder父类
- */
public class SecondAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private List<PhoneBean>list = new ArrayList<>();
public void refresh(List<PhoneBean>list){
this.list.addAll(list);
notifyDataSetChanged();
}
//根据list中按position获取的type值返回
//返回数据以参数的是形式onCreateViewHolder第二参数
@Override
public int getItemViewType(int position) {
return list.get(position).type;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int i) {
View view = null;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
if (i==0){//i代表的是类型
view = inflater.inflate(R.layout.item_title,viewGroup,false);
return new TitleViewHolder(view);
}else {
view = inflater.inflate(R.layout.item_values,viewGroup,false);
return new PhoneViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (list.get(i).type==0){//i代表的是下标
//首字母
TitleViewHolder vh = (TitleViewHolder) viewHolder;
vh.mTitle.setText(list.get(i).title);
}else {
//联系人详情
PhoneViewHolder vh = (PhoneViewHolder) viewHolder;
vh.mName.setText(list.get(i).name);
vh.mPhone.setText(list.get(i).phone);
}
}
@Override
public int getItemCount() {
return list.size();
}
//多布局操作->1布局对应1ViewHolder
//首字母布局对应的ViewHolder
class TitleViewHolder extends RecyclerView.ViewHolder{
TextView mTitle;
public TitleViewHolder(@NonNull View itemView) {
super(itemView);
mTitle = itemView.findViewById(R.id.title_Tv);
}
}
//联系人详情对应的ViewHolder
class PhoneViewHolder extends RecyclerView.ViewHolder{
TextView mName;
TextView mPhone;
public PhoneViewHolder(@NonNull View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.name1_Tv);
mPhone = itemView.findViewById(R.id.phone1_Tv);
}
}
}
六.使用多布局实现淘宝首页
1.适配器代码
/**Rv适配器,包含多个头布局
* Created by yusheng on 2016/11/28.
*/
public class RvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {
/**普通商品的(normalHolder)的标题集合,调用者传入*/
private List<String> normalGoodsTitls;
/**头布局总数*/
private int HEADER_CONUNT=7;
public RvAdapter(List<String> normalGoodsTitls) {
this.normalGoodsTitls = normalGoodsTitls;
}
private int HEADER0 = 0;
private int HEADER1 = 1;
private int HEADER2 = 2;
private int HEADER3 = 3;
private int HEADER4 = 4;
private int HEADER5 = 5;
private int HEADER6 = 6;
private int NORMAL = 100;
private View headView0;
private View headView1;
private View headView2;
private View headView3;
private View headView4;
private View headView5;
private View headView6;
public void setHeadView0(View headView0) {
this.headView0 = headView0;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == HEADER0) {
return new BannerHolder(headView0);
}else if(viewType==HEADER1){
return new GridMenuHolder(headView1);
}else if (viewType==HEADER2){
return new HeadlinesHolder(headView2);
}else if(viewType==HEADER3){
return new SnapUpHolder(headView3);
}else if(viewType==HEADER4){
return new MiddleBannerHolder(headView4);
}else if(viewType==HEADER5){
return new HotMatketHolder(headView5);
}else if(viewType==HEADER6){
return new GoodsTrendHolder(headView6);
}
else {
return new NormalHolder(View.inflate(UIUtils.getContext(), R.layout.rv_item_normal, null));
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
Log.d("alan","holder位置---》"+holder.getLayoutPosition());
if (viewType == HEADER0 ) {
return;
}else if(viewType==HEADER1){
return;
}else if(viewType==HEADER2){
return;
}else if (viewType==HEADER3){
return;
}else if(viewType==HEADER4){
return;
}else if(viewType==HEADER5){
return;
}else if (viewType==HEADER6){
return;
}
else if(viewType==NORMAL){
NormalHolder normalHolder= (NormalHolder) holder;
final int realPostion=position-HEADER_CONUNT;//获取真正的位置
if (mOnItemClickLitener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = realPostion;
mOnItemClickLitener.onItemClick(holder.itemView, pos);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View v)
{
int pos = realPostion;
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return true;
}
});
}
// Log.d("alan","位置-->"+position);
normalHolder.tv_title.setText(normalGoodsTitls.get(realPostion));
normalHolder.iv_goodsLeft.setOnClickListener(this);
normalHolder.iv_goodsLeft.setTag(realPostion);
normalHolder.iv_goodsRight.setOnClickListener(this);
normalHolder.iv_goodsRight.setTag(realPostion);
}
}
@Override
public int getItemViewType(int position) {
if (position == 0 && headView0 != null) {
return HEADER0;
}else if(position==1&&headView1!=null){
return HEADER1;
}else if(position==2&&headView2!=null){
return HEADER2;
}else if (position==3&&headView3!=null){
return HEADER3;
}else if (position==4&&headView4!=null){
return HEADER4;
}else if (position==5&&headView5!=null){
return HEADER5;
}else if(position==6&&headView6!=null){
return HEADER6;
}
else {
return NORMAL;
}
}
//有7条普通数据,但是要加上Header的总数
@Override
public int getItemCount() {
return normalGoodsTitls.size()+HEADER_CONUNT;
}
/**
* 添加顶部banner
*/
public void addHeadView0(View view) {
this.headView0 = view;
}
/**添加10个子菜单*/
public void addHeaderView1(View v) {
this.headView1 = v;
}
/**添加淘宝头条*/
public void addHeaderView2(View v){
this.headView2=v;
}
/**添加抢购的Header*/
public void addHeaderView3(View v){
this.headView3=v;
}
/**中间的banner*/
public void addHeaderView4(View v){
this.headView4=v;
}
public void addHeaderView5(View v){
this.headView5=v;
}
public void addHeaderView6(View v){
this.headView6=v;
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.iv_goodsLeft:
int postion= (int) v.getTag();
UIUtils.showToast("shoes left"+"\n"+"postion "+postion);
break;
case R.id.iv_goodsRight:
int postion2= (int) v.getTag();
UIUtils.showToast("shoes right"+"\n"+"postion "+postion2);
break;
}
}
//顶部banner
class BannerHolder extends RecyclerView.ViewHolder {
public BannerHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
//10个子菜单
class GridMenuHolder extends RecyclerView.ViewHolder{
public GridMenuHolder(View itemView) {
super(itemView);
}
}
//普通的Holder
class NormalHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_goodsLeft)
ImageView iv_goodsLeft;
@BindView(R.id.iv_goodsRight)
ImageView iv_goodsRight;
@BindView(R.id.tv_title)
TextView tv_title;
public NormalHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
/**淘宝头条HOlder*/
class HeadlinesHolder extends RecyclerView.ViewHolder{
public HeadlinesHolder(View itemView) {
super(itemView);
}
}
/**抢购的Header(4个)*/
class SnapUpHolder extends RecyclerView.ViewHolder{
public SnapUpHolder(View itemView) {
super(itemView);
}
}
/**中间的banner*/
class MiddleBannerHolder extends RecyclerView.ViewHolder{
public MiddleBannerHolder(View itemView) {
super(itemView);
}
}
/**热门市场*/
class HotMatketHolder extends RecyclerView.ViewHolder{
public HotMatketHolder(View itemView) {
super(itemView);
}
}
/**热门市场下面的潮流商品*/
class GoodsTrendHolder extends RecyclerView.ViewHolder{
public GoodsTrendHolder(View itemView) {
super(itemView);
}
}
public interface OnItemClickListener{
void onItemClick(View v,int postion);
void onItemLongClick(View v,int postion);
}
/**自定义条目点击监听*/
private OnItemClickListener mOnItemClickLitener;
public void setmOnItemClickLitener(OnItemClickListener mOnItemClickLitener) {
this.mOnItemClickLitener = mOnItemClickLitener;
}
}
练习手册
技能一:
https://www.apiopen.top/satinApi?type=1&page=2
要求:
1.模拟快手App主页面 图片 点赞量
2.使用recyclerview实现瀑布流效果
3.图片和图片的边距2dp
4.效果要好看.
5.长按图片删除要有动画效果(点击事件使用接口回调+不能产生错位现象)
技能二:
6.使用recyclerview展示数据
7.实现左右多布局
8.点击发送按钮将消息发送出去
9.使用Glide加载圆形头像
技能三:
1.使用内容提供者查询手机联系人
2.将查询出来的联系人展现在recyclerview中
3.要求有ABCD标题和联系人的格式不一样,使用多布局完成
4.点击右边的listview,左测跟着滑动