Android中ListView与RecyclerView的详解与使用【附Project压缩包】
ListView简介
ListView可以用来展示数据的控件,最熟悉的像qq里的好友列表,就可以通过Listview来实现。ListView可以理解为一个由很多行view组成的列表,而view通过绑定item改变自身的样式。
ListView的最简单的使用
一:在activiy_main.XML中写入一个ListView
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/l_1"/>
二:在MainActivity中声明数据,这里以一组String数据为例
private String[] data = {"1", "2", "3", "4", "5"};
三:构造适配器,这里的适配器泛型指向String类型,item是系统内置的item
ArrayAdapter<String> adapter=new ArrayAdapter<String>
(MainActivity.this,android.R.layout.simple_list_item_1,data);
四:Listview传入适配器
ListView listView=(ListView)findViewById(R.id.l_1);//ListView的id
listView.setAdapter(adapter);
是不是非常简单?但是这只是最基本的使用,没有经过任何的优化。
ListView的优化
显然一个listview只能显示文字是非常单调的
一:指定自己设置的item
新建一个item.xml,写入一个Button和ImageView
<ImageView
android:id="@+id/fruit_image"
android:layout_width="80dp"
android:layout_height="80dp" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp" />
二:新建一个类(以水果类为例)
public class fruit {
private String name;
private int imageId;
public fruit(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
public String getName() {
return name;
}
public int getImageId() {
return imageId;
}
}
三 :有了水果类,,因为原本的ArrayAdapter已经无法满足水果类传入ListView的要求了,需要一个新的适配器。注释的部分代码是运行效率优化前的代码,当ListView是滚动时,原来的代码会就不断地读取item的布局和id,修改后的代码会将读取的布局和id存储在缓存内,需要时再拿出来使用。
public FA(Context context, int textViewResourceId, List<fruit> objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
fruit fruit = getItem(position);
// View view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//可以优化,优化部分如下
View view;//避免重新加载布局
ViewHolder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
viewHolder = new ViewHolder();
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
// ImageView fruitImage=(ImageView)view.findViewById(R.id.fruit_image);
// TextView fruitName=(TextView) view.findViewById(R.id.fruit_name);
// fruitImage.setImageResource(fruit.getImageId());
// fruitName.setText(fruit.getName());
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());//避免重新读取fruitname和fruitIamge,将这两个信息存储在viewholderr中,再将viewholder放置在view的标签内
return view;
}
class ViewHolder {
ImageView fruitImage;
TextView fruitName;
}
}
四:传入ListView并添加点击事件
private List<fruit> fruitlist = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inintfruit();//初始化水果列表
FA adapter = new FA(MainActivity.this, R.layout.fruit_item, fruitlist);
ListView listView = (ListView) findViewById(R.id.l_1);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {//item点击事件
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
fruit fruit = fruitlist.get(position);
Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
listView.setAdapter(adapter);//传入adapter
}
private void inintfruit() {//准备的图片太少,只能循环已到达滚动的 目的
for (int i = 0; i < 5; i++) {//图片在项目中有
fruit apple = new fruit("Apple", R.drawable.apple_pic);
fruitlist.add(apple);
fruit banana = new fruit("banana", R.drawable.banana_pic);
fruitlist.add(banana);
fruit orange = new fruit("orange", R.drawable.orange_pic);
fruitlist.add(orange);
}
}
最终的效果如下
RecyclerView
RecyclerView比ListView好,好在哪几个地方呢?
一:ListView能实现的RecyclerView也能实现
二:除了一,它还能实现横向滚动,瀑布流滚动(类似于淘宝的浏览界面)
三:它的点击方法通过view实现,这就意味之能更方便的实现点击子项里的某一个控件(例如Image和TextView)
RecyclerView的简单使用(其实一点也不简单)
一:最关键的一步,当然是引入包了。把下面这行代码添加到build.gradle的dependencies 中,然后同步一下(点击右上角的Sync now)
implementation ‘androidx.recyclerview:recyclerview:1.0.0’//添加recyclerview.jar包
二:在activity_main.xml中添加一个RecyclerView界面
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyle_view"></androidx.recyclerview.widget.RecyclerView>
三:把之前ListView的item.xml和Fruit类copy过来,图片也复制过来(能copy绝对不写)
四:创建适配器并在适配器中实现点击事件和加载item布局。这个适配器很好理解,就是代码多了点
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
class ViewHolder extends RecyclerView.ViewHolder {
View fruitView;
ImageView fruitImage;
TextView fruitaName;
public ViewHolder(View view) {
super(view);
fruitView=view;
fruitaName = (TextView) view.findViewById(R.id.fruit_name);
fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
}
}
public FruitAdapter(List<Fruit> fruitList) {
mFruitList = fruitList;
}
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);//传入item布局
final ViewHolder holder=new ViewHolder(view);
holder.fruitView.setOnClickListener(new View.OnClickListener() {//view的点击事件
@Override
public void onClick(View v) {
int postion=holder.getAdapterPosition();
Fruit fruit=mFruitList.get(postion);
Toast.makeText(v.getContext(),"you clicked view"+fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
//ViewHolder holder=new ViewHolder(view);
holder.fruitImage.setOnClickListener(new View.OnClickListener() {//item里的图片点击事件
@Override
public void onClick(View v) {
int postion=holder.getAdapterPosition();
Fruit fruit=mFruitList.get(postion);
Toast.makeText(v.getContext(),"you clicked image"+fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit=mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitaName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
}
五:修改MainActivity里的代码,主要目的有三个,指定RecyclerView的布局(瀑布流布局),声明一个适配器,传入适配器到RecyclerView中
private List<Fruit> fruitList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruit();
RecyclerView recyclerView =(RecyclerView)findViewById(R.id.recyle_view);
// LinearLayoutManager layoutManager=new LinearLayoutManager(this);//纵/横向布局
StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);//三列的瀑布流布局
// layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//改为纵向布局
FruitAdapter adapter=new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruit(){
for (int i=0;i<5;i++) {
Fruit apple =new Fruit(getRandomLengthName("Apple"),R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana =new Fruit(getRandomLengthName("Banana"),R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange =new Fruit(getRandomLengthName("Orange"),R.drawable.orange_pic);
fruitList.add(orange);
}
}
private String getRandomLengthName(String name){//这一段的目的是为了将一些文字重复以证明瀑布流布局的是真的三列。
Random random =new Random();
int length=random.nextInt(20)+1;
StringBuilder builder=new StringBuilder();
for (int i=0;i<length;i++){
builder.append(name);
}
return builder.toString();
}
然后最终效果如下
点击(View时)