如何建设好一个网站/旺道seo软件技术
文章目录
- 一、简介
- 二、基本自定义使用
- 1.activity_main里定义控件
- 2.自定义Adapter
- (1)给条目创建一个Class类
- (2)给条目创建一个布局
- (3)自定义Adapter
- 3.在MainActivity中使用
- 三、点击事件
- 1.修改onCreaterViewHolder()
- 2.例子:
- 四、出错原因
- 1.控件id引用错误
- 2.List容器问题
一、简介
RecyclerView控件可以说是ListView的升级版,尤其是RecyclerView解决了ListView上控件和条目点击冲突的问题。
Google官方也推荐使用RecyclerView代替ListView。
二、基本自定义使用
这样的效果:很明显这是两个Item条目,每个Item里面有一个文本TextView和一张图片ImageView。
1.activity_main里定义控件
这个很简单,就和Button控件一样。
<?xml version="1.0" encoding="utf-8"?>
<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"><androidx.recyclerview.widget.RecyclerViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/rl"/></LinearLayout>
2.自定义Adapter
我们将RecyclerView的每个Item称为条目。
我们要作的事情有三步:
- 给条目创建一个Class类
- 给条目创建一个布局
- 自定义Adapter
(1)给条目创建一个Class类
- 文本TextView是String字符串
- 图片ImageView是int资源索引id
- 按钮之类的就不用写,因为不需要赋值。
package com.example.hello;public class Fruit {private String mName;private int mImageId;public Fruit(String name,int ImageId){mName=name;mImageId=ImageId;}public String getmName(){return mName;}public int getmImageId(){return mImageId;}
}
(2)给条目创建一个布局
这个布局是用来排布条目内部的布局。这个加layout.xml
<?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="wrap_content"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/fruit_name"/><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/fruit_image"/></LinearLayout>
(3)自定义Adapter
定义Adapter才是考验技术的时刻。
package com.example.hello;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {private List<Fruit> mFruitList;static class ViewHolder extends RecyclerView.ViewHolder{TextView fruitName;ImageView fruitImage;public ViewHolder(View view){super(view);fruitName=view.findViewById(R.id.fruit_name);fruitImage=view.findViewById(R.id.fruit_image);}}public FruitAdapter(List<Fruit> fruitList){mFruitList=fruitList;}@Overridepublic int getItemCount() {return mFruitList.size();}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.layout,parent,false);ViewHolder viewHolder=new ViewHolder(view);return viewHolder;}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {Fruit fruit=mFruitList.get(position);holder.fruitName.setText(fruit.getmName());holder.fruitImage.setImageResource(fruit.getmImageId());}
}
-
分析FruitAdapter类的继承:
RecyclerView.Adapter<FruitAdapter.ViewHolder>
。-
我们肯定是要继承RecyclerView的东西,而我们是定义Adapter,那就是RecyclerView.Adapter。
-
里面的模板参数是
自定义Adapter的名字.ViewHolder
,这个ViewHolder是我们自定义的一个内部类。
-
-
分析成员变量和构造函数:
private List<Fruit> mFruitList
和public FruitAdapter(List<Fruit> fruitList)
-
这个List成员变量表示一个条目的内容,如String的值和图片的索引id。
-
到时候我们的使用的时候,是传一个List容器进来,所以构造函数是这样。也因此需要一个List成员变量来保存传进来的List容器,而且成员方法也需要用到List。
-
-
分析静态类ViewHolder:
- 为什么要继承?
因为RecyclerView.ViewHolder是个抽象类,所以必须继承才能使用。 - 这个构造方法作用?
这个构造方法就是像在MainActivity.class里面绑定Button控件一样,将控件和条目内部的布局里的id通过findViewById()绑定在一起。 - ViewHolder的作用理解:
我认为ViewHolder其实就是一个把控件View整合在一起的仓库Holder,里面的东西不就是把各个View声明和findViewById()的过程写在一起。
这样整合到一起后,就很方便。
- 为什么要继承?
-
分析三个重写的成员方法
-
必须重写,少写报错。
因为RecyclerView.Adapter也是个抽象类,所以必须重写它的这个三个方法:onCreateViewHolder()、onBindViewHolder()和getItemCount()。 -
onCreateViewHolder()
用于创建ViewHolder实例的。
我们在这个方法中将条目的布局加载到View中,然用View创建一个ViewHolder实例,并把加载出来的布局传入到构造函液当中,最后将ViewHolder的实例返回。 -
onBindViewHolder()
用于对RecyclerView子项的数据进行赋值的。
会在每个子项被滚动到屏幕内的时候执行(滚动到屏幕内才执行,这就是优化),这里我们通过position参数得到当前项的Fruit实例,然后再将数据设置到ViewHolder的ImageView和TextView当中即可。 -
getltemCountO
告诉RecyclerView一共有多少子项,直接返回成员变量List的长度就可以了。
-
3.在MainActivity中使用
package com.example.hello;import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);recyclerView=findViewById(R.id.rl);//构造一个List对象List<Fruit> fruitList=new ArrayList<>();fruitList.add(new Fruit("banana",R.drawable.banana));fruitList.add(new Fruit("watermelon",R.drawable.watermelon));//设置RecyclerView的条目在RecyclerView中的排布布局LinearLayoutManager linearLayoutManager=new LinearLayoutManager(MainActivity.this);recyclerView.setLayoutManager(linearLayoutManager);//设置RecyclerView的AdatperFruitAdapter mFruitAdapter=new FruitAdapter(fruitList);recyclerView.setAdapter(mFruitAdapter);}
}
三、点击事件
1.修改onCreaterViewHolder()
只需要在FruitAdapter里做一点修改,比ListView简单多了。
冲突解决机制:
这个控件可以是条目布局里面的控件或者条目本身。当你没有点击特定的条目里的控件时,就是认为点击条目本身。
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item,parent,false);ViewHolder viewHolder=new ViewHolder(view);viewHolder.控件.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {}});return viewHolder;
}
- 在ViewHolder构造里声明条目本身点击:
View myView=view
,view是ViewHolder里传进来的参数 - 在setOnClickListener()中
获得点击条目的下标(从0开始):int pos=viewHolder.getAdapterPosition();
获得上下文:view.getContext()
,用MainActivity.class报错。
2.例子:
package com.example.hello;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import java.util.List;public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {private List<Fruit> mFruitList;static class ViewHolder extends RecyclerView.ViewHolder{View fruitView;TextView fruitName;ImageView fruitImage;public ViewHolder(View view){super(view);fruitView=view;fruitName=view.findViewById(R.id.fruit_name);fruitImage=view.findViewById(R.id.fruit_image);}}public FruitAdapter(List<Fruit> fruitList){mFruitList=fruitList;}@Overridepublic int getItemCount() {return mFruitList.size();}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.layout,parent,false);final ViewHolder viewHolder=new ViewHolder(view);viewHolder.fruitView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {int pos=viewHolder.getAdapterPosition();Toast.makeText(view.getContext(),"你点击了条目,位置"+pos,Toast.LENGTH_SHORT).show();}});viewHolder.fruitImage.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {int pos=viewHolder.getAdapterPosition();Toast.makeText(view.getContext(),"你点击了图片,位置"+pos,Toast.LENGTH_SHORT).show();}});viewHolder.fruitName.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {int pos=viewHolder.getAdapterPosition();Toast.makeText(view.getContext(),"你点击了名字,位置"+pos,Toast.LENGTH_SHORT).show();}});return viewHolder;}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {Fruit fruit=mFruitList.get(position);holder.fruitName.setText(fruit.getmName());holder.fruitImage.setImageResource(fruit.getmImageId());}
}
四、出错原因
1.控件id引用错误
static class ViewHolder extends RecyclerView.ViewHolder
{TextView itemName;TextView itemProgress;Button itemBtn;public ViewHolder(View view){super(view);itemName=view.findViewById(R.id.name);itemProgress=view.findViewById(R.id.progress);itemBtn=view.findViewById(R.id.show);}
}
文件多了,控件id就容易记混。比如,itemBtn应该绑定的是R.id.btn。
2.List容器问题
Adapter中的List不用new ArrayList<>(),因为List在构造参数会传入一个实例参数。
而Activity中的List必须new ArrayList<>(),因为List要在Activity中添加数据,否则会报错java.lang.NullPointerException。