Android view.settran,Android RecyclerView从入门到玩坏
目录
前言
基础使用
分隔线
点击监听
搭配CardView
更丰富的条目
增删条目
快速添加视图
让RecyclerView支持复杂视图
最后前言
RecyclerView在Android界面开发当中是很重要的, 那掌握它也是很必要的. 但是有些时候会觉得它很厚重, 这里就从RecyclerView的基础一直说到扩展, 让你把RecyclerView学薄了.
这篇文章融合了自己原来的多篇文章, 并进行了修正和改进, 而且添加了很多很有趣的内容.
本文需要20分钟以上的阅读时间, 请合理安排.
多图预警, 转载请注明出处!
基础使用
要使用RecyclerView在Android Studio 2.x(以下简称AS), 要这样:
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
到了AS 3.x, 要这样:
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0'
之后在布局文件中写入如下代码就引入了RecyclerView了.
android:id="@+id/rv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
布局类
效果LinearLayoutManager
以垂直或水平滚动列表方式显示项目
GridLayoutManager
在网格中显示项目
StaggeredGridLayoutManager
在分散对齐网格中显示项目mRvMain = (RecyclerView) findViewById(R.id.rv_main);
// 设置布局
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
mRvMain.setLayoutManager(linearLayoutManager);
最关键的还是适配器的撰写. 但是理解起来不是很难, 你只要将ListView的适配器写法带入理解就好. 这里把全部代码贴出来, 因为后面要在这个基础上不断扩充.
public class MyRVAdapter2 extends RecyclerView.Adapter {
private final LayoutInflater mLayoutInflater;
private final Context mContext;
private final ArrayList mData;
public MyRVAdapter2(Context context) {
mLayoutInflater = LayoutInflater.from(context);
mContext = context;
mData = new ArrayList<>();
for (int i = 0; i < 40; i++) {
mData.add("hello " + i);
}
}
@Override
public MyRVAdapter2.MyTVHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyRVAdapter2.MyTVHolder(mLayoutInflater.inflate(R.layout.rv_txt_item, parent, false));
}
@Override
public void onBindViewHolder(final MyRVAdapter2.MyTVHolder holder, int pos) {
holder.mTextView.setText(mData.get(pos));
}
@Override
public int getItemCount() {
return mData == null ? 0 : mData.size();
}
class MyTVHolder extends RecyclerView.ViewHolder {
TextView mTextView;
MyTVHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.tv_txt);
}
}
}
然后写个最基础的TextView条目. 让它跑起来看看效果.
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:id="@+id/tv_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="@dimen/eight_dp"
android:text="@string/tmp"
android:textSize="@dimen/thirty_sp" />
分隔线
前面的部分已经是基础的RecyclerView使用了. 那比起ListView是不是没有了分隔线. 这里上一个简单好用的开源库RecyclerView-FlexibleDivider.
引入:
implementation 'com.yqritc:recyclerview-flexibledivider:1.4.0'
使用:
mRvMain.addItemDecoration(
new HorizontalDividerItemDecoration.Builder(this).build());
看效果就达到了吧.
觉得不好看, 还可以自定义, 更多写法可以参见文档内容.
mRvMain.addItemDecoration(
new HorizontalDividerItemDecoration.Builder(this)
.color(Color.BLUE)
.sizeResId(R.dimen.two_dp)
.marginResId(R.dimen.eight_dp, R.dimen.eight_dp)
.build());
而且而且, 竖着的分隔线也大丈夫哦.
GridLayoutManager gridLayoutManager
= new GridLayoutManager(this, 2);
mRvMain.setLayoutManager(gridLayoutManager);
mRvMain.addItemDecoration(
new VerticalDividerItemDecoration.Builder(this).build());
点击监听
再回忆一下在天国的ListView, 还有item的点击吧, 这个也要自己写.
适配器中:
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
private MyRVAdapter2.OnItemClickListener mOnItemClickListener;
public void setOnItemClickListener(MyRVAdapter2.OnItemClickListener mOnItemClickListener) {
this.mOnItemClickListener = mOnItemClickListener;
}
onBindViewHolder中设置点击监听.
@Override
public void onBindViewHolder(final MyRVAdapter2.MyTVHolder holder, int pos) {
holder.mTextView.setText(mData.get(pos));
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickListener.onItemClick(holder.itemView, pos);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickListener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
使用监听:
mAdapter.setOnItemClickListener(new MyRVAdapter2.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(UIUtil.getContext(), "click" + position, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(UIUtil.getContext(), "long click" + position, Toast.LENGTH_SHORT).show();
}
});
搭配CardView
是不是这个点击看着没啥感觉, 没事, 我们换上CardView再来一次.
布局文件:
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/eight_dp"
android:foreground="@drawable/card_foreground"
card_view:cardCornerRadius="@dimen/four_dp">
android:id="@+id/tv_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="@dimen/eight_dp"
android:text="@string/tmp"
android:textSize="@dimen/thirty_sp" />
给CardView加上水波纹点击特效:
android:color="@color/colorPrimary" />
在老版本就只能用选择器了, 其实效果也还好:
android:drawable="@drawable/card_foreground_selector"
android:insetBottom="@dimen/four_dp"
android:insetLeft="@dimen/three_dp"
android:insetRight="@dimen/three_dp"
android:insetTop="@dimen/four_dp" />
更丰富的条目
大家应该都知道TextView可以设置图标吧, 这里来看下效果图, 顺带感受下android界面设计语言的变化.
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:id="@+id/tv_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@mipmap/ic_launcher"
android:drawablePadding="@dimen/sixteen_dp"
android:drawableStart="@mipmap/ic_launcher"
android:gravity="center_vertical"
android:padding="@dimen/eight_dp"
android:text="@string/tmp"
android:textSize="@dimen/thirty_sp" />
让GridLayoutManager展示不同宽度的条目
方的是4.x上的, 圆的是8.x上的, 可以看到, 变化还是很大的. 我们回正题. GridLayoutManager布局是可以设置宽度的, 不一定都是一样大的, 来看下实现.
// 指定item宽度
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position == 0
|| position == (mAdapter.getItemCount() - 1) / 2
|| position == (mAdapter.getItemCount() - 1)) {
return gridLayoutManager.getSpanCount();
} else {
return 1;
}
}
});
来看效果图, 发现我们的分隔线崩了是吧, 如果真想用这个分隔线也还是要自己动手修补修补, 改动改动, 开源库再棒也猜不到你的项目需求呀.
当然了, 我还是很喜欢这个分隔线的, 我们来看看横着滚动的效果.
布局文件要改动:
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
android:id="@+id/tv_txt"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="@string/tmp"
android:textSize="@dimen/thirty_sp" />
gridLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
展示不同布局
之前变化宽度其实还是相同条目, 现在要展示不同条目:
写一个图的条目:
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/eight_dp">
android:id="@+id/iv_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:class="lazyload" src="https://img-blog.csdnimg.cn/2022010702381440793.png" data-original="@mipmap/ic_launcher" />
public enum ITEM_TYPE {
ITEM_TYPE_IMAGE,
ITEM_TYPE_TEXT
}
这里多了判断条目类型, 还要注意返回值的变化, 用了更基类的RecyclerView.ViewHolder.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal()) {
return new MyRVAdapter2.MyIVHolder(mLayoutInflater.inflate(R.layout.rv_img_item, parent, false));
} else {
return new MyRVAdapter2.MyTVHolder(mLayoutInflater.inflate(R.layout.rv_txt_item, parent, false));
}
}
类继承上面也要变成RecyclerView.ViewHolder, 这些都是要对应的.
extends RecyclerView.Adapter
当然了, holder也是不能少的.
public class MyIVHolder extends RecyclerView.ViewHolder {
ImageView mImageView;
MyIVHolder(View view) {
super(view);
mImageView = (ImageView) view.findViewById(R.id.iv_img);
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int pos) {
if (holder instanceof MyRVAdapter2.MyTVHolder) {
((MyRVAdapter2.MyTVHolder) holder).mTextView.setText(mData.get(pos));
} else if (holder instanceof MyRVAdapter2.MyIVHolder) {
((MyRVAdapter2.MyIVHolder) holder).mImageView.setImageDrawable(UIUtil.getDrawable(R.mipmap.ic_launcher));
}
// 点击监听
...
}
顺带的, 我们把之前放宽的条目变成不同的视图, 也就是对应起来:
@Override
public int getItemViewType(int position) {
if (position == 0
|| position == (getItemCount() - 1) / 2
|| position == (getItemCount() - 1)) {
return ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal();
} else {
return ITEM_TYPE.ITEM_TYPE_TEXT.ordinal();
}
}
看看效果:
它还能继续地复杂, 试试瀑布流StaggeredGridLayoutManager:
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/eight_dp"
card_view:cardCornerRadius="@dimen/four_dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:id="@+id/iv_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:class="lazyload" src="https://img-blog.csdnimg.cn/2022010702381440793.png" data-original="@mipmap/ic_launcher" />
android:id="@+id/tv_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/tmp"
android:textSize="@dimen/thirty_sp" />
StaggeredGridLayoutManager staggeredGridLayoutManager
= new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
mRvMain.setLayoutManager(staggeredGridLayoutManager);
分割线又崩了, 嘿嘿, 其实用上了CardView, 分割线没什么必要再用了.
增删条目
现在适配器中添加增删方法:
public void addData(int position) {
mData.add(position, "hello x");
notifyItemInserted(position);
}
public void removeData(int position) {
mData.remove(position);
notifyItemRemoved(position);
}
再写入点击事件中, 点击增加, 长按删除:
mAdapter.setOnItemClickListener(new MyRVAdapter2.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
mAdapter.addData(position);
}
@Override
public void onItemLongClick(View view, int position) {
mAdapter.removeData(position);
}
});
增删条目开源库
这里再上一个开源库recyclerview-animators, 可以修改增删动画, 种类也很丰富, 还能在它基础上自定义:
分类
动画类名Cool
LandingAnimator
Scale
ScaleInAnimator, ScaleInTopAnimator, ScaleInBottomAnimator, ScaleInLeftAnimator, ScaleInRightAnimator
Fade
FadeInAnimator, FadeInDownAnimator, FadeInUpAnimator, FadeInLeftAnimator, FadeInRightAnimator
Flip
FlipInTopXAnimator, FlipInBottomXAnimator, FlipInLeftYAnimator, FlipInRightYAnimator
Slide
SlideInLeftAnimator, SlideInRightAnimator, OvershootInLeftAnimator, OvershootInRightAnimator, SlideInUpAnimator, SlideInDownAnimator引入:
implementation 'jp.wasabeef:recyclerview-animators:2.3.0'
使用:
mRvMain.setItemAnimator(new SlideInLeftAnimator());
这里给大家展示两种效果, 其它的自己尝试吧.
mRvMain.setItemAnimator(new LandingAnimator());
快速添加视图
还有像Header, Foot这样的视图, 自己写也还是要费些功夫的, 这里推荐Android大神的库baseAdapter
引入:
implementation 'com.zhy:base-rvadapter:3.0.3'
添加头尾视图
HeaderAndFooterWrapper mHeaderAndFooterWrapper = new HeaderAndFooterWrapper(mAdapter);
TextView t1 = new TextView(this);
t1.setText("Header 1");
t1.setTextSize(30);
TextView t2 = new TextView(this);
t2.setText("Foot 1");
t2.setTextSize(30);
mHeaderAndFooterWrapper.addHeaderView(t1);
mHeaderAndFooterWrapper.addFootView(t2);
mRvMain.setAdapter(mHeaderAndFooterWrapper);
添加更多视图
LoadMoreWrapper mLoadMoreWrapper = new LoadMoreWrapper(mAdapter);
mLoadMoreWrapper.setLoadMoreView(R.layout.rv_cv_img_txt_item);
mLoadMoreWrapper.setOnLoadMoreListener(new LoadMoreWrapper.OnLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
}
});
mRvMain.setAdapter(mLoadMoreWrapper);
是不是感觉特别爽, 那看看更爽的, 在不写适配器的情况下快速添加条目:
final ArrayList mData = new ArrayList<>();
for (int i = 0; i < 40; i++) {
mData.add("hello " + i);
}
mRvMain.setAdapter(new CommonAdapter(this, R.layout.rv_cv_txt_item, mData) {
@Override
protected void convert(ViewHolder holder, String s, int position) {
holder.setText(R.id.tv_txt, mData.get(position));
}
});
是不是感觉省了一万个小时呢.
让RecyclerView支持复杂视图
每次加入新的视图都要对适配器进行比较大程度的改动, 这样是很容易出错的. 这里引入一个非常棒的开源库-AdapterDelegates, 降低下代码耦合性.
引入:
implementation 'com.hannesdorfmann:adapterdelegates3:3.0.1'
先不说使用细节, 来看看实现后想加入不同视图有多简单吧:
ArrayList data = new ArrayList<>();
for (int i = 0; i < 10; i++) {
data.add(new B("b " + i));
}
for (int i = 0; i < 10; i++) {
data.add(new A("a " + i));
}
BaseAdapter animalAdapter = new BaseAdapter(this, data);
mRvMain.setAdapter(animalAdapter);
是不是惊了, 也就是说, 你只要实现了A, B这些视图类, 直接新建放入数组就完事了.
需要写基础适配器:
public class BaseAdapter extends RecyclerView.Adapter {
private AdapterDelegatesManager> delegatesManager;
private List items;
public BaseAdapter(Activity activity, List items) {
this.items = items;
delegatesManager = new AdapterDelegatesManager<>();
delegatesManager.addDelegate(new AAdapterDelegate(activity))
.addDelegate(new BAdapterDelegate(activity));
}
@Override
public int getItemViewType(int position) {
return delegatesManager.getItemViewType(items, position);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return delegatesManager.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
delegatesManager.onBindViewHolder(items, position, holder);
}
@Override
public int getItemCount() {
return items.size();
}
}
需要对每个类进行进行具体设置, 这里以A为例.
public class AAdapterDelegate extends AdapterDelegate> {
private LayoutInflater inflater;
public AAdapterDelegate(Activity activity) {
inflater = activity.getLayoutInflater();
}
@Override
public boolean isForViewType(@NonNull List items, int position) {
return items.get(position) instanceof A;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new CatViewHolder(inflater.inflate(R.layout.rv_cv_img_txt_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull List items, int position,
@NonNull RecyclerView.ViewHolder holder, @Nullable List payloads) {
CatViewHolder vh = (CatViewHolder) holder;
A cat = (A) items.get(position);
vh.name.setText(cat.getName());
}
static class CatViewHolder extends RecyclerView.ViewHolder {
public TextView name;
public ImageView img;
public CatViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.tv_txt);
img = (ImageView) itemView.findViewById(R.id.iv_img);
}
}
}
最后
看完这篇应该是对RecyclerView有个大体认识了, 多练习练习就会得心应手起来了. 那还是有一点, 就像分隔线库的几次不理想表现, 具体项目要求还是要具体对待, 开源库也不是万能的. 最近不是又有什么开源项目套壳事件了嘛, 别人一开源就说自己有自主产权了真的好吗? 喜欢记得点赞或者关注我哦, 有意见或者建议评论区见~
Android view.settran,Android RecyclerView从入门到玩坏相关推荐
- android view选中状态,RecyclerView选中
###**RecyclerView选中状态** ~~~ package com.wxx.fragmentaction.recycler; import android.content.Context; ...
- android view嵌套,Android RecyclerView嵌套RecyclerView点击事件
RecyclerView嵌套RecyclerView点击事件遇到取值错乱的问题 其实问题根本就是咱们没有处理好被嵌套的那层recycleview的position 那么解决思路也很简单,想办法把被嵌套 ...
- android view禁用,Android 禁止ViewPager的自带滑动效果
由于最近在做墨水屏的相关工作,ViewPager自带的滑动效果在墨水屏上表现的很不好,残影太重了.所以禁止自带的滑动效果,用接口来接管相关逻辑实现自处理. import android.content ...
- Android view变形,android仿变形金刚效果实现MatchView
what?变形金刚!先看效果吧! MainActivity.javapackage com.lee.matchview; import com.example.matchview.R; import ...
- android.view.surface,Android SurfaceView 源码分析及使用
概述 SurfaceView 是 Android 中一种比较特殊的视图(View),它跟平时时候的 TextView.Button 最大的区别是它跟它的视图容器并不是在同一个视图层上,它的 UI 显示 ...
- android view flipper,Android之ViewFlipper的简单使用
大家都使用过ViewPager,但是ViewPager还有一个兄弟,那就是ViewFlipper.两者的名字非常相似,我们可以将ViewPager理解成"一页一页的视图",View ...
- android view 虚线分割线,RecyclerView设置分割线---DividerItemDecoration
官方提供的分割线处理方案,也是继承的RecyclerView.ItemDecoration实现的. divider.png 用法很简单,注释里面有demo.同时也可以通过自定义drawable来实现d ...
- android view setleft,android – 在新textview上使用setLeft / setRight方法
我正在以编程方式使用TextViews,我需要动态添加新视图并在RelativeLayout父级中设置它们的左/顶位置. 我正在做的是这样的: RelativeLayout global=(Relat ...
- android view 平滑,Android移动view动画问题(让移动更平滑)
Android写动画效果不是一般的麻烦,网上找了好久,终于解决了动画的问题,总结记录以共勉. 仅以水平方向移动效果做说明,垂直方向类似. 完整动画函数代码: public void slideview ...
最新文章
- vue 组件以字符串插入_今日分享:vue3多层嵌套组件如何访问到最外层组件的数据?...
- 【Alertmanager】腾讯企业邮箱配置
- go io.reader 多次读取_Go 经典入门系列 24:Select
- 了解Scaffold Generator (转载)
- java slf4j_SLF4J 使用手册
- 关于Linux线程的线程栈以及TLS
- Dell PowerEdge R740xd可以做什么?
- 在使用DelphiXE3和SQLite3进行程序开发时,解决最后一个字符乱码的问题
- javascript紧接上一张for循环的问题,我自己的理解
- php数组array_filter,php数组array_filter()函数和array_slice()函数
- 【历史上的今天】8 月 31 日:人工智能起源;GPU诞生;Windows 98中文版来了
- 室内定位之蓝牙定位精度(蓝牙AOA定位)
- 专升本C语言必刷编程题
- 计算智能3--进化计算
- kubernetes 1.10.3 cAdvisor + Heapster + InfluxDB + Grafana
- Android开发 之 OpenGL ES系列(5--3D立体图形)
- Docker推送镜像到自己的阿里云卡住,也不报错
- 理县“有福童享”“牵手圆梦 陪伴成长”关爱折翼天使志愿服务活动
- 信息系统项目管理师-业务流程管理知识点
- Android 存储相册,Android 相册图片存储
热门文章
- java音频实时传输_会议室智能系统建设方案,实时远程视频协作
- html中两个图片叠放,CSS实现图片叠放(勾选图标)
- python多线程输出_萌新python多线程
- python词云乱码_python词云库wordCloud使用方法详解(解决中文乱码)
- jdbc mysql分页_JDBC【数据库连接池、DbUtils框架、分页】
- Latex 表格 行合并,列合并,控制行间距 单元格宽度
- 编写第二个Spring程序——AOP实现
- 理解lua中 . : self
- EMC VMAX的磁盘构成,fast policy(重要)
- windows(win7,win8,xp)hosts文件找不到原因分析及解决方法