简介
RecyclerView是什么
从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传统的ListView,更加强大和灵活。RecyclerView的官方定义如下:
A flexible view for providing a limited window into a large data set.
从定义可以看出,flexible(可扩展性)是RecyclerView的特点。
RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字Recyclerview即回收view也可以看出。
优点
RecyclerView并不会完全替代ListView(这点从ListView没有被标记为@Deprecated可以看出),两者的使用场景不一样。但是RecyclerView的出现会让很多开源项目被废弃,例如横向滚动的ListView, 横向滚动的GridView, 瀑布流控件,因为RecyclerView能够实现所有这些功能。
RecylerView相对于ListView的优点如下:
·RecyclerView封装了viewholder的回收复用,也就是说RecyclerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。
·提供了一种插拔式的体验,高度的解耦,异常的灵活,针对一个Item的显示RecyclerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。
·设置布局管理器以控制Item的布局方式,横向、竖向以及瀑布流方式
·可设置Item的间隔样式(可绘制)
通过继承RecyclerView的ItemDecoration这个类,然后针对自己的业务需求去书写代码。
·可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecyclerView有其自己默认的实现。
但是关于Item的点击和长按事件,需要用户自己去实现。
重要方法·
1.RecyclerView横向滑动:
LinearLayoutManager.HORIZONTAL横向滑动LinearLayoutManager.VERTICAL垂直滑动
2.RecyclerView.Adapter中刷新方法区别:
notifyDataSetChanged();整体刷新+没有动画效果
notifyItemInserted(int position,Object data):有动画效果+添加一条数据在position位置
notifyItemRemoved(position);有动画效果+删除一条数据并刷新
注意:当添加和删除的时候,要更新下标,不然有错位现象
先在集合中删除要删除的数据
之后
myRecyclerViewAdapter.notifyItemRangeChanged(0,arrayList.size());
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.导入依赖
implementation ‘com.android.support:recyclerview-v7:28.0.0’
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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/my_recycler_view">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
2.适配器
点击事件(接口回调)
public interface MyClickListener {
void onItemClick(int i);
}
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
ArrayList<HashMap<String,String>> arrayList;
Context context;
MyClickListener myClickListener;
public MyAdapter(ArrayList<HashMap<String, String>> arrayList, Context context,MyClickListener myClickListener) {
this.arrayList = arrayList;
this.context = context;
this.myClickListener = myClickListener;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = View.inflate(context,R.layout.item,null);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, final int i) {
myViewHolder.textView.setText(arrayList.get(i).get("title"));
myViewHolder.textView2.setText(arrayList.get(i).get("intro"));
Glide.with(context).load(arrayList.get(i).get("strUrl")).apply(RequestOptions.bitmapTransform(new RoundedCorners(20))).into(myViewHolder.imageView);
myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myClickListener.onItemClick(i);
}
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
TextView textView,textView2;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.item_img);
textView = itemView.findViewById(R.id.item_txt);
textView2 = itemView.findViewById(R.id.item_txt2);
}
}
}
实现多布局(联系人)
注意添加权限
适配器
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
ArrayList<MyContent> arrayList;
Context context;
public MyRecyclerViewAdapter(ArrayList<MyContent> arrayList, Context context) {
this.arrayList = arrayList;
this.context = context;
}
@Override
public int getItemViewType(int position) {
return arrayList.get(position).getFlag();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (i == 0){
View view = LayoutInflater.from(context).inflate(R.layout.item_title,viewGroup,false);
return new TitleViewHolder(view);
}else {
View view = LayoutInflater.from(context).inflate(R.layout.item_phone,viewGroup,false);
return new PhoneViewHolder(view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (arrayList.get(i).getFlag() == 0){
TitleViewHolder titleViewHolder = (TitleViewHolder) viewHolder;
titleViewHolder.textView.setText(arrayList.get(i).getPhonebook_label());
}else {
PhoneViewHolder phoneViewHolder = (PhoneViewHolder) viewHolder;
phoneViewHolder.textView.setText(arrayList.get(i).getName()+" "+arrayList.get(i).getPhoneNum());
}
}
@Override
public int getItemCount() {
Log.e("####",arrayList.size()+"");
return arrayList.size();
}
class TitleViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public TitleViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.item_title);
}
}
class PhoneViewHolder extends RecyclerView.ViewHolder{
TextView textView;
public PhoneViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.item_phone);
}
}
}
联系人 类
public class MyContent {
private String name;
private String phoneNum;
private String phonebook_label;
private int flag;
public MyContent(String name, String phoneNum, String phonebook_label, int flag) {
this.name = name;
this.phoneNum = phoneNum;
this.phonebook_label = phonebook_label;
this.flag = flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public String getPhonebook_label() {
return phonebook_label;
}
public void setPhonebook_label(String phonebook_label) {
this.phonebook_label = phonebook_label;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "MyContent{" +
"name='" + name + '\'' +
", phoneNum='" + phoneNum + '\'' +
", phonebook_label='" + phonebook_label + '\'' +
", flag=" + flag +
'}';
}
}
Activity
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
ArrayList<MyContent> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT > 23){
int i = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
if (i == PackageManager.PERMISSION_DENIED){
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS,Manifest.permission.WRITE_CONTACTS},60);
}
}
recyclerView = findViewById(R.id.my_recycler_view);
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, null, null, null, "phonebook_label");
String str = "";
while (cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String phonebook_label = cursor.getString(cursor.getColumnIndex("phonebook_label"));
MyContent myContent = new MyContent(name, phoneNum, phonebook_label, 1);
Log.e("####",phonebook_label);
if (str.equals(phonebook_label)){
arrayList.add(myContent);
}else {
arrayList.add(new MyContent(null,null,phonebook_label,0));
arrayList.add(myContent);
str = phonebook_label;
}
}
MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(arrayList, this);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(myRecyclerViewAdapter);
myRecyclerViewAdapter.notifyItemRangeChanged(0,arrayList.size());
}
}
随机高度瀑布流
imageView = itemView.findViewById(R.id.video);
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.height = (int) (Math.random() * 200+400);
imageView.setLayoutParams(layoutParams);
textView = itemView.findViewById(R.id.textview);
item行布局ImageView添加的属性
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitXY"
android:id="@+id/item_img"/>
XRecyclerview的使用:上拉加载 下拉刷新
与Recyclerview使用基本相同
导入依赖
implementation ‘com.android.support:recyclerview-v7:28.0.0’
api(‘com.jcodecraeer:xrecyclerview:1.5.9’) {
exclude group: ‘com.android.support’
}
布局(布局显示为灰色 不影响)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.jcodecraeer.xrecyclerview.XRecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/my_recycler_view"
android:background="#FFFFFF">
</com.jcodecraeer.xrecyclerview.XRecyclerView>
</LinearLayout>
item布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#E6DFDF"
android:padding="10dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitXY"
android:id="@+id/item_img"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:id="@+id/item_txt"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:id="@+id/item_txt2"/>
</LinearLayout>
适配器
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
ArrayList<HashMap<String,String>> arrayList;
Context context;
MyClickListener myClickListener;
public MyAdapter(ArrayList<HashMap<String, String>> arrayList, Context context,MyClickListener myClickListener) {
this.arrayList = arrayList;
this.context = context;
this.myClickListener = myClickListener;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = View.inflate(context,R.layout.item,null);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, final int i) {
myViewHolder.textView.setText(arrayList.get(i).get("title"));
myViewHolder.textView2.setText(arrayList.get(i).get("intro"));
Glide.with(context).load(arrayList.get(i).get("strUrl")).apply(RequestOptions.bitmapTransform(new RoundedCorners(20))).into(myViewHolder.imageView);
myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myClickListener.onItemClick(i);
}
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
TextView textView,textView2;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.item_img);
textView = itemView.findViewById(R.id.item_txt);
textView2 = itemView.findViewById(R.id.item_txt2);
}
}
}
点击事件接口
public interface MyClickListener {
void onItemClick(int i);
}
全局变量
public class MyApplication extends Application {
String strUrl;
}
Activity
public class MainActivity extends AppCompatActivity {
XRecyclerView recyclerView;
ArrayList<HashMap<String,String>> arrayList;
static int i = 1;
@SuppressLint("HandlerLeak")
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1001){
myAdapter.notifyDataSetChanged();
recyclerView.loadMoreComplete();
recyclerView.refreshComplete();
}
}
};
MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.my_recycler_view);
arrayList = new ArrayList<>();
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager);
myAdapter= new MyAdapter(arrayList, MainActivity.this, new MyClickListener() {
@Override
public void onItemClick(int i) {
MyApplication application = (MyApplication) MainActivity.this.getApplication();
application.strUrl = arrayList.get(i).get("strUrl");
Intent intent = new Intent(MainActivity.this, Main2Activity.class);
startActivity(intent);
}
});
recyclerView.setAdapter(myAdapter);
getJson();
// 可以设置是否开启加载更多/下拉刷新
recyclerView.setLoadingMoreEnabled(true);
recyclerView.setPullRefreshEnabled(true);
// 如果设置上这个,下拉刷新的时候会显示上次刷新的时间
recyclerView.getDefaultRefreshHeaderView() // get default refresh header view
.setRefreshTimeVisible(true); // make refresh time visible,false means hiding
recyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
i = 1;
arrayList.clear();
getJson();
}
@Override
public void onLoadMore() {
i++;
getJson();
}
});
}
private void getJson(){
OkGo.<String>get("https://www.apiopen.top/satinApi?type=1&page="+i).execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
String body = response.body();
try {
JSONObject jsonObject = new JSONObject(body);
JSONArray data = jsonObject.getJSONArray("data");
for (int i = 0; i < data.length(); i++){
JSONObject jsonObject1 = data.getJSONObject(i);
String name = jsonObject1.getString("name");
String text = jsonObject1.getString("text");
String strUrl = jsonObject1.getString("videouri");
if (strUrl.isEmpty()){
continue;
}
HashMap<String, String> map = new HashMap<>();
map.put("title",name);
map.put("intro",text);
map.put("strUrl",strUrl);
arrayList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onFinish() {
super.onFinish();
handler.sendEmptyMessage(1001);
}
@Override
public void onError(Response<String> response) {
super.onError(response);
Log.e("####",response.body()+"");
}
});
}
}
跳转的Activity
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main2Activity">
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/my_video_view"/>
</LinearLayout>
public class Main2Activity extends AppCompatActivity {
VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
videoView = findViewById(R.id.my_video_view);
MyApplication application = (MyApplication) getApplication();
videoView.setVideoPath(application.strUrl);
videoView.requestFocus();
videoView.start();
videoView.setMediaController(new MediaController(this));
}
}
常用方法:
万能适配器
project中的gradle添加
maven {
url ‘https://jitpack.io’
}
导入依赖
implementation ‘com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.42’
implementation ‘com.android.support:recyclerview-v7:28.0.0’
适配器
public class MyAdapter extends BaseQuickAdapter<Bean,BaseViewHolder> {
private Context context;
public MyAdapter(int layoutResId, @Nullable List<Bean> data,Context context) {
super(layoutResId, data);
this.context = context;
}
@Override
protected void convert(BaseViewHolder helper, Bean item) {
helper.setText(R.id.item_txt,item.getTitle());
Glide.with(context).load(item.getImgUrl())
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into((ImageView) helper.getView(R.id.item_img));
}
}
Bean
public class Bean {
private String title;
private String imgUrl;
public Bean(String title, String imgUrl) {
this.title = title;
this.imgUrl = imgUrl;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
}
@Override
public String toString() {
return "Bean{" +
"title='" + title + '\'' +
", imgUrl='" + imgUrl + '\'' +
'}';
}
}
Activity
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
MyAdapter myAdapter;
ArrayList<Bean> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.my_recycler_view);
getData();
myAdapter = new MyAdapter(R.layout.item,arrayList,this);
recyclerView.setAdapter(myAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
public void getData(){
OkGo.<String>get("http://www.qubaobei.com/ios/cf/dish_list.php?stage_id=1&limit=20&page=1").execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
String body = response.body();
try {
JSONObject jsonObject = new JSONObject(body);
JSONArray data = jsonObject.getJSONArray("data");
for (int i = 0; i < data.length(); i++){
JSONObject jsonObject1 = data.getJSONObject(i);
String title = jsonObject1.getString("title");
String pic = jsonObject1.getString("pic");
Bean bean = new Bean(title, pic);
arrayList.add(bean);
}
} catch (JSONException e) {
e.printStackTrace();
}
myAdapter.notifyDataSetChanged();
}
@Override
public void onError(Response<String> response) {
super.onError(response);
Log.e("####",response.body());
}
});
}
}