首先在activity_main中加入ListView控件。
而后修改MainActivity中的代码
public class MainActivity extends AppCompatActivity { String[] data = {"apple","banana","orange","watermelon","banana","orange","watermelon","banana","orange","watermelon","banana","orange","watermelon","banana","orange","watermelon","banana","orange","watermelon","banana","orange","watermelon","banana","orange","watermelon"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); ArrayAdapter adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1,data); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView> parent, View view, int position, long id) { String fruit = data[position]; Toast.makeText(MainActivity.this,fruit,Toast.LENGTH_SHORT).show(); } }); } }
ArrayAdapter
ArrayAdapter
对象,它是Android中用于将数据绑定到ListView
、GridView
等组件的适配器之一。
表示这个适配器是用来处理字符串(String)类型的数据。new ArrayAdapter<>(...
表示实例化一个ArrayAdapter
对象。MainActivity.this
是当前MainActivity
的上下文(Context),这通常用于获取系统服务或启动其他组件。android.R.layout.simple_list_item_1
是一个系统提供的布局资源,用于定义列表项的样式。这里指定了列表项的布局,该布局显示单个文本项。data
是一个字符串数组,它包含了要显示在列表中的所有数据。ListView listView = (ListView) findViewById(R.id.list_view);
findViewById
方法来获取布局文件中定义的ListView
组件的实例。R.id.list_view
是ListView
组件在布局文件中的ID。ListView
是Android中的一个组件,用于显示垂直滚动的列表项。listView.setAdapter(adapter);
adapter
设置为listView
的适配器。setAdapter
是ListView
的一个方法,用于将适配器绑定到列表视图上,这样列表视图就可以显示适配器中的数据了。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; } }
而后为ListView的子项指定一个自定义的布局,在layout目录下新建一个fruit_item.xml
接着我们需要创建一个自定义的适配器,这个适配器继承自ArrayAdapter,并将泛型是定位Fruit类
public class FruitAdapter extends ArrayAdapter { private int resourceId; public FruitAdapter(@NonNull Context context, int textViewResourceId, List objects) { super(context, textViewResourceId,objects); resourceId = textViewResourceId; } @NonNull @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); 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()); return view; } }
public class FruitAdapter extends ArrayAdapter {
FruitAdapter
的公共类,它继承自ArrayAdapter
类,并且指定了泛型参数Fruit
,这意味着这个适配器是专门为处理Fruit
类型对象的列表而设计的。private int resourceId;
resourceId
,用于存储列表项的布局资源ID。public FruitAdapter(@NonNull Context context, int textViewResourceId, List objects) {
FruitAdapter
的构造函数,它接受三个参数: @NonNull Context context
:上下文对象,用于访问系统服务和资源。int textViewResourceId
:列表项的布局资源ID。List objects
:一个包含Fruit
对象的列表,这些对象将被显示在列表中。super(context, textViewResourceId, objects);
ArrayAdapter
的构造函数,传递上下文、资源ID和对象列表。public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
ArrayAdapter
中的getView
方法,它是适配器的核心,用于为列表中的每个项提供视图。int position
:当前项在列表中的位置。@Nullable View convertView
:可重用的视图,用于提高列表滚动的性能。@NonNull ViewGroup parent
:列表视图的父容器。Fruit fruit = getItem(position);
ArrayAdapter
的getItem
方法,获取列表中当前位置的Fruit
对象。View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
LayoutInflater
从getContext()
获取的上下文中实例化一个视图,使用resourceId
指定的布局资源,并且parent
是列表视图的父容器,false
表示不要为parent
添加这个视图。
LayoutInflater.from(getContext())
LayoutInflater
是一个用于将XML布局文件转换成实际视图对象的系统服务。from(context)
是一个静态方法,它返回一个LayoutInflater
的实例,并且已经配置了给定的上下文(context
)。getContext()
- 这是
ArrayAdapter
类的一个方法,返回当前适配器的上下文(Context
)。上下文是Android中非常重要的概念,它提供了对系统服务的访问以及对资源的引用。inflate(resourceId, parent, attachToRoot)
inflate
是LayoutInflater
类的一个方法,用于将指定资源ID的XML布局文件实例化为视图对象。resourceId
:是一个整型值,指定了要实例化的布局资源的ID。parent
:是一个ViewGroup
对象,表示新创建的视图将要被添加到的父容器。在这个上下文中,parent
参数通常是用来确保新视图的布局参数正确设置的。attachToRoot
:是一个布尔值,指定是否将新创建的视图附加到parent
。在这个例子中,false
表示不附加到parent
,而是返回一个独立的视图对象,稍后可以手动添加到parent
。综合来看,
LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
这行代码的作用是:
- 从当前适配器的上下文中获取
LayoutInflater
实例。- 使用
inflate
方法将指定的布局资源ID(resourceId
)转换成实际的视图对象。- 将这个新创建的视图作为子视图,但不立即附加到提供的父容器(
parent
)上。- 返回这个新创建的视图对象,以便可以在适配器的
getView
方法中进一步设置和返回。
ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
findViewById
获取布局中的ImageView
组件,用于显示水果的图片。TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
findViewById
获取布局中的TextView
组件,用于显示水果的名称。fruitImage.setImageResource(fruit.getImageId());
ImageView
的图片资源,getImageId()
是Fruit
类的一个方法,返回图片资源的ID。fruitName.setText(fruit.getName());
TextView
的文本,getName()
是Fruit
类的一个方法,返回水果的名称。return view;
FruitAdapter
类通过重写getView
方法,为每个列表项提供了自定义的视图布局,包括水果的图片和名称。这使得列表项不仅显示文本,还可以显示图像,从而提供更丰富的用户界面。
这一步骤只需要替换上一阶段中的适配器对象即可,此处略过。
将FruitAdapter中的代码进行优化。
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Fruit fruit = getItem(position); View view; if(convertView == null){ view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false); }else{ view = convertView; } 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()); return view; }
convertView
,减少了布局的创建和视图的初始化次数。这对于长列表来说尤其重要,因为它可以显著减少内存使用和提高滚动性能。public class FruitAdapter extends ArrayAdapter { private int resourceId; public FruitAdapter(@NonNull Context context, int textViewResourceId, List objects) { super(context, textViewResourceId,objects); resourceId = textViewResourceId; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Fruit fruit = getItem(position); View view; ViewHolder viewHolder; if(convertView == null){ view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false); viewHolder = new ViewHolder(); viewHolder.fruitImage = view.findViewById(R.id.fruit_image); viewHolder.fruitName = view.findViewById(R.id.fruit_name); view.setTag(viewHolder); }else{ view = convertView; viewHolder = (ViewHolder) view.getTag(); } viewHolder.fruitImage.setImageResource(fruit.getImageId()); viewHolder.fruitName.setText(fruit.getName()); return view; } class ViewHolder { ImageView fruitImage; TextView fruitName; } }
此控件早在远古时代的16年就被淘汰。
由于该组件不是内置在系统SDK中,所以需要把完整的包路径写出来。
public class FruitAdapter extends RecyclerView.Adapter { private List mFruitList; static class ViewHolder extends RecyclerView.ViewHolder{ ImageView fruitImage; TextView fruitName; public ViewHolder(View itemView) { super(itemView); fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image); fruitName = (TextView) itemView.findViewById(R.id.fruit_name); } } public FruitAdapter(List mFruitList) { this.mFruitList = mFruitList; } @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent,false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Fruit fruit = mFruitList.get(position); holder.fruitImage.setImageResource(fruit.getImageId()); holder.fruitName.setText(fruit.getName()); } @Override public int getItemCount() { return mFruitList.size(); } }
这段代码定义了一个名为FruitAdapter
的类,它扩展了RecyclerView.Adapter
,用于在RecyclerView
中显示水果列表。
public FruitAdapter(List mFruitList)
Fruit
对象的列表。static class ViewHolder extends RecyclerView.ViewHolder
ViewHolder
,用于缓存视图组件的引用,减少重复调用findViewById
。@Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
ViewHolder
实例。这个方法负责为每个列表项提供视图。@Override public void onBindViewHolder(@NonNull ViewHolder holder, int position)
ViewHolder
上。这个方法负责将每个列表项的数据填充到视图中。@Override public int getItemCount()
RecyclerView
用来确定显示多少项的方法。Fruit
对象的列表,并将其存储在适配器中。ViewHolder
的构造函数中,通过调用itemView.findViewById
获取视图中的组件(如ImageView
和TextView
),并将它们存储在ViewHolder
实例中。LayoutInflater
从parent.getContext()
获取的上下文中加载布局资源(R.layout.fruit_item
),并将其实例化为视图。ViewHolder
实例,并将新创建的视图传递给ViewHolder
的构造函数。ViewHolder
实例。position
参数获取列表中对应位置的Fruit
对象。ViewHolder
中的组件引用(fruitImage
和fruitName
)来设置视图的图片资源和文本。Fruit
对象列表的大小,即列表项的总数。private List fruitList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); initFruits(); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); FruitAdapter adapter = new FruitAdapter(fruitList); recyclerView.setAdapter(adapter); } initFruits();
initFruits
的方法,这个方法可能是用来初始化一个包含Fruit
对象的列表,这些对象将被用于填充RecyclerView
。RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
findViewById
方法,获取布局文件中定义的RecyclerView
组件的实例,并将其转换为RecyclerView
类型。LinearLayoutManager layoutManager = new LinearLayoutManager(this);
LinearLayoutManager
对象,用于管理RecyclerView
中的项如何布局。this
关键字指的是当前的上下文(可能是一个Activity
或Fragment
)。recyclerView.setLayoutManager(layoutManager);
LinearLayoutManager
设置为RecyclerView
的布局管理器,这样RecyclerView
就知道如何对其子项进行布局。FruitAdapter adapter = new FruitAdapter(fruitList);
FruitAdapter
对象,并将之前初始化的fruitList
(包含Fruit
对象的列表)传递给它。这个适配器将用于将数据绑定到RecyclerView
。recyclerView.setAdapter(adapter);
FruitAdapter
设置为RecyclerView
的适配器。这样RecyclerView
就有了数据源,并且知道如何显示这些数据。RecyclerView
是 Android 中一个灵活的组件,用于展示大量数据集,它可以配合不同的布局管理器(LayoutManager
)来实现横向滚动、瀑布流布局和网格布局。以下是实现这些布局的基本步骤:
横向滚动通常使用 LinearLayoutManager
并设置其方向为横向。
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); recyclerView.setLayoutManager(layoutManager);
瀑布流布局是一种不规则的网格布局,可以实现不同高度和宽度的项。
StaggeredGridLayoutManager
实例:StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager);
网格布局使用 GridLayoutManager
来实现。
GridLayoutManager
实例:GridLayoutManager layoutManager = new GridLayoutManager(this, spanCount); recyclerView.setLayoutManager(layoutManager);
RecyclerView
的布局管理器:recyclerView.setLayoutManager(layoutManager);
@Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent,false); ViewHolder holder = new ViewHolder(view); //注册文字监听事件 holder.fruitName.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(view.getContext(),"外层", Toast.LENGTH_SHORT).show(); } }); //注册图片按钮监听事件 holder.fruitImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(view.getContext(),"图片", Toast.LENGTH_SHORT).show(); } }); return holder; }