单条目的实现比较简单 (V7包下的)RecyclerView 提供的强大的适配器 让我们 用的十分方便 我们先来讲解适配器!
这个Adapter 中存在一个 泛型 <> 这个泛型可以是 它自身提供的 RecyclerView.ViewHolder
也(或者)
同样可以是 我们自己自定义的 如:MyAdapter.ViewHolder (这个名字是自己自定义的) 注意:这个看上去很麻烦的步骤,事实上你只需通过款借鉴就可以轻松的搞定了~alt+enter 一直按到不报红
next
private Context context; //创建一个上下文 跟其他的列表控件一样
//创建一个 数据 集合 (这里new 出来是为了防止 后续有些人出现空指针,不要细扣!)
private ArrayList<String> list = new ArrayList<>();
//构造器,有参
public MyAdapter(Context context) {
this.context = context;
}
//set方法(不多做解释!),你可以写的详细点~
public void setList(ArrayList<String> list) {
this.list = list;
}
重写了一下这3个方法!
第一个:
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
//这个方法中的参数说明:
//参1:父布局
//参2:item 也就是条目的下标(通俗的意思就是 第几条? 从 0 开始的!!)
}
第二个:请活用这个方法!切记不要死记硬背 未来自定义的监听事件都是在这里写的
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
//这个方法的参数说明:
//参1:这个viewHolder 返回的 是 子条目,也就是 当前条目(通俗的意思是给你的布局文件在这里赋值)
//参2:这个下标i 是你传进来的集合的 下标! (如:list.get(i))
}
第三个:
@Override
public int getItemCount() {
//这个方法的参数说明:
//参1:这个方法会返回一个你的数据集合的总条数
return list.size()>0?list.size():0;
}
具体代码结构:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
//取得你的XML 中的布局文件 这里这样写的原因是,如果你不声明你的父布局,那么你的布局文件中的 尺寸会被压缩,
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_one, viewGroup, false);
//你也可以换一种写法 View.inflate() 用这个方法返回的布局依然可以用~
//将你的布局 添加到这个 holder 中去
//这里会提示你创建 该类 你可以选择创建在内部,同时也可以是外部的
return new HolderOne(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
//你可以利用参数 将你 赋值的过程拿到一个外部类去进行 如: HolderOne.setData(list.get(i)) 这会提示你建立一个方法
String s = list.get(i);
//将这个布局 强转成 HolderOne 类型的 然后对其进行操作
HolderOne viewHolder1 = (HolderOne) viewHolder;
viewHolder1.setData(s);
}
//不多解释!!!!!
@Override
public int getItemCount() {
return list.size()>0?list.size():0;
}
private class HolderOne extends RecyclerView.ViewHolder {
//这里顺便介绍一个 implementation 'cn.bingoogolapple:bga-banner:2.2.4@aar' 的用法
//创建一个 图片的数组!
private String[] picUrl = {
"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2938240330,1839732672&fm=27&gp=0.jpg",
"http://img3.imgtn.bdimg.com/it/u=4276491126,3511500973&fm=27&gp=0.jpg",
"http://img5.imgtn.bdimg.com/it/u=210464971,3093822652&fm=27&gp=0.jpg"
};
//创建一个文字的数组
private String[] picDesc = {
"兰博基尼",
"奔驰",
"法拉利"
};
final List<String> imgList = new ArrayList<>(); //创建 图片的地址集合
List<String> imgDesc = new ArrayList<>(); //创建 图片说明文字的地址集合
private final BGABanner banner; //在该类中全局 声明属性
public HolderOne(View view) {
super(view);
//利用这个view 找到 这个自定义的第三方控件
banner = view.findViewById(R.id.banner_indicatorId);
}
//这个是上边的 代码所新建出来的方法 s 是传过来的参数
public void setData(String s) {
//通过遍历的形式 来讲图片数组中的数据添加到集合之中,顺便将 文字也加入
for (int a = 0; a < picUrl.length; a++) {
imgList.add(picUrl[a]);
imgDesc.add(picDesc[a]);
}
//set这两个集合
banner.setData(imgList,imgDesc);
//自定义控件的适配器
banner.setAdapter(new BGABanner.Adapter<ImageView,String>() {
@Override
public void fillBannerItem(BGABanner banner, ImageView itemView, String model, int position) {
Picasso.with(context).load(imgList.get(position)).fit().into(itemView);
}
});
}
}
添加重写方法
@Override
public int getItemViewType(int position) {
//这里是三种布局类型 一旦这个方法生效 你的 @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) 中的i 就会变成你返回的 数值 .这个返回的类型你可以定义静态常量 那样规范一些
if(position==0){
return 0;
}else if(position==1){
return 1;
}else {
return position;
}
}
//对应的布局 改成对应的holder类
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
//这里的if 同样可以写成 if( getItemViewType(i) ==0 ) 这样写 也可以!但是 大前提 是你要 重写 getItemViewType 这个方法!
if(i==0){
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_one, viewGroup, false);
return new HolderOne(view);
}else if(i==1){
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_two, viewGroup, false);
return new HOlderTwo(view);
}else {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_three, viewGroup, false);
return new HolderThree(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
String s = list.get(i);
//这里的 holder 可以复用 我没写
//这里的 instanceof 是一个关键字 替换的意思 依照你holder所属的类判断
//比如一个 对一个 object 进行判断 首先你要知道它是什么 类
// if ( object instanceof String ) 如果它是string 类的
//同样也可以 根据 getItemViewType(int position) 所得到的 返回值 进行判断
if(viewHolder instanceof HolderOne){
HolderOne viewHolder1 = (HolderOne) viewHolder;
viewHolder1.setData(s);
}else if(viewHolder instanceof HOlderTwo){
HOlderTwo viewHolder2 = (HOlderTwo) viewHolder;
viewHolder2.setData(s);
}else {
HolderThree viewHolder3 = (HolderThree) viewHolder;
viewHolder3.setData(s);
}
}
end
在Activity 中 创建对象
MyAdapter adapter = new MyAdapter(this);
创建布局管理者 一共有三种样式:
//参数参照 上边的图片 填写
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//参数参照 上边的图片 填写
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
gridLayoutManager.setOrientation(GridLayoutManager.VERTICAL);
gridLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
//参数参照 上边的图片 填写
StaggeredGridLayoutManager staggeredGridLayoutManager
= new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
该适配器中的一些常用API
更新列表position位置上的数据可以调用
.notifyItemChanged(int position)
列表position位置添加一条数据时可以调用,伴有动画效果
.notifyItemInserted(int position)
列表position位置移除一条数据时调用,伴有动画效果
.notifyItemRemoved(int position)
列表fromPosition位置的数据移到toPosition位置时调用,伴有动画效果
.notifyItemMoved(int fromPosition, int toPosition)
列表从positionStart位置到itemCount数量的列表项进行数据刷新
.notifyItemRangeChanged(int positionStart, int itemCount)
列表从positionStart位置到itemCount数量的列表项批量添加数据时调用,伴有动画效果
.notifyItemRangeInserted(int positionStart, int itemCount)
列表从positionStart位置到itemCount数量的列表项批量删除数据时调用,伴有动画效果
.notifyItemRangeRemoved(int positionStart, int itemCount)
最后我们将
将参数传递至该控件
RecyclerView控件 .setAdapter(adapter);
RecyclerView控件 .setLayoutManager(linearLayoutManager);
思想:在该类中,或者是外部中 创建一个 接口 定义 若干个 方法,利用接口回调 触发该方法
注意:你要用 条目去 触发 点击事件 在onBindViewHolder 的方法中去写 并且在这个控件中你可以监听 有关于这个条目中 的 子控件的事件
具体的 写法 将于之后更新
myAdapter2.setOnClickListener(new MyAdapter.ItemCallBack() {
@Override
public void click(int i) {
//这里是一个 关于删除 条目的坑 会用点击的人可以看一下 注意一下这里
list.remove(i);
myAdapter2.notifyItemRemoved(i);
myAdapter2.notifyItemRangeChanged(i,list.size()-i);
}
});
//一个RecyclerView 滚动的 方法
public static void Scroll(RecyclerView recyclerView, final boolean isV , final onEvent onEvent){
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
//用来标记是否正在向最后一个滑动
boolean isSlidingToLast = false;
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
//设置什么布局管理器,就获取什么的布局管理器
LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
// 当停止滑动时
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
//获取最后一个完全显示的ItemPosition ,角标值
int lastVisibleItem = manager.findLastCompletelyVisibleItemPosition();
//所有条目,数量值
int totalItemCount = manager.getItemCount();
// 判断是否滚动到底部,并且是向右滚动
if (lastVisibleItem == (totalItemCount - 1) && isSlidingToLast) {
onEvent.info();
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//dx用来判断横向滑动方向,dy用来判断纵向滑动方向
//dx>0:向右滑动,dx<0:向左滑动
//dy>0:向下滑动,dy<0:向上滑动
if(isV){
if (dy > 0) {
isSlidingToLast = true;
} else {
isSlidingToLast = false;
}
}else {
if (dx > 0) {
isSlidingToLast = true;
} else {
isSlidingToLast = false;
}
}
}
});
}