ListView和RecyclerView学习

ListView

ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

在MainActivity中

public class MainActivity extends AppCompatActivity {

    private String[] data = {"Apple","Banana","Orange","Watermelon","Pear",
            "Grape","Pineapple","Strawberry","Cherry","Mango",
            "Apple","Banana","Orange","Watermelon","Pear",
            "Grape","Pineapple","Strawberry","Cherry","Mango",};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView listView = (ListView) findViewById(R.id.list_view);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,
                android.R.layout.simple_list_item_1,data);
        listView.setAdapter(adapter);
    }
}

● data 是ListView中要显示的数据,可以自定义,也可以从后台获取
● ArrayAdapter 数据无法直接传给ListView,需要借助适配器来完成。而ArrayAdapter是Android中提供的适配器实现类,可以通过泛型来指定要适配的数据类型。
● ArrayAdapter 构造函数参数一:当前上下文;参数二:ListView子项布局的id;参数三:要适配的数据。
● android.R.layout.simple_list_item_1 是一个Android内置的布局,里面只有一个TextView,可用于简单地显示一段文本。
● listView.setAdapter() 通过该方法将构建好的适配器对象传递进去,这样ListView和数据之间就建立

定制ListView的界面

ListView的子项布局正常情况下不止一段文本,我们可以对ListView进行界面的定制

第一,定义一个实体类,作为ListView适配器的适配对象
新建类Fruit

public class Fruit
{
	private String name;
	private int imageId;
	public Fruit(String _Name,int _Id) {
        Name = _Name;
        Id = _Id;
    }
    public String getName() {return this.Name;}
    public int getId(){return this.Id;}
}

name表示水果的名字,imageId表示水果对应图片的资源id。

第二 自定义ListView的子项布局

<?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="horizontal">
    <ImageView
        android:id="@+id/fruitimage"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content">
    </ImageView>

    <TextView
        android:id="@+id/fruittext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </TextView>
</LinearLayout>

第三 自定义适配器
这个适配器继承ArrayAdapter,并将泛型指定为Fruit类。

public class FruitAdapter extends ArrayAdapter<Fruit>{
private int resourceId;
public FruitAdapter(Context cotext,int textViewResourceId,List<Fruit> objects)
	{
		super(context,textViewResourceId,object);
		resourceId=textViewResourceId;
	}
	public View getView(int position,View converView,ViewGroup parent)
	{
		Fruit fruit=getItem(position);
		View view=LayoutInflater.from(getContext()).inflate(resourId,parent,false);
		ImageView  fruiteImage= view.findViewById(R.id.fruit_image);
        TextView fruitName= view.findViewById(R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId);
        furitName.setText(fruit.getName());
        return view;
   }
 }

● FruitAdapter 重写父类个构造函数,将上下文、ListView子项布局id和数据传递进来
● 重写getView()方法。每个子项滚动到屏幕内时都会调用这个方法。
● getItem()方法得到当前项的Fruit实例
● LayoutInflater 为子项加载我们传入的布局
● inflate()方法的参数三要传入false,表示只让我们在父布局中声明的layout生效,但不会为这个View添加父布局,因为View一旦有了父布局,就不能将它添加到ListView中
● 调用View的findViewById()方法分别获取到ImageView和TextView的实例,然后分别调用setImageResource()和setText()来设置显示图片和文字

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initFruits();
    ListView listView = (ListView) findViewById(R.id.list_view);
    FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, mFruitList);
    listView.setAdapter(adapter);
	//注册监听器
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Fruit fruit = mFruitList.get(position);
            Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
        }
    });
}

RecyclerView

ListView只能实现数据纵向滚动效果,无法实现横向滚动,且效率低下。因此Android提供了一个增强版的ListView——RecyclerView。
RecyclerView属于新增的控件,为了让RecyclerView在所有的版本上都能适用,Android团队采用同样的方式,将RecyclerView定义在了support库中.

implementation 'androidx.recyclerview:recyclerview:1.0.0'

由于RecyclerView并不是内置在系统SDK当中的,所以需要把完整的包路径写出来。
main_activity.xml

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </androidx.recyclerview.widget.RecyclerView>

Fuit和frui_item_xml参考ListView
下来准备RecyclerView适配器。
1.创建适配器类继承·RecyclerView.Adapter并且把泛型指定为FruitAdapter.ViewHolder。
2.创建内部类ViewHolder即RecyclerView.ViewHolder的子类
3.重写RecyclerView.Adapter的各种方法

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>
{
	private List<Fruit> mFruitList;
	static class ViewHolder extends RecyclerView.Holder
	{
		ImageView fruitImage;
		ImageView fruitName;
		public ViewHolder(View view)
		{
			super(view);
			fruitImage=(ImageView)view.findViewById(R.id.furit_image);
			fruitName=(TextView)view.findViewById(R.id.furit_name);
		}
	}
	public FruitAdapter(List<Fruit> fruitList)
	{
			mFruitList=fruitList;
	}
	public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType)
	{
		View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
		ViewHolder holder=new ViewHolder(view);
		return holder;
	}
	public void onBindViewHolder(ViewHolder holder,int position)
	{
		Fruit fruit=mFruitList.from(positon);
		holder.furitImage.setImageResource(fruit.getImageId());
		holder.furitName.setText(furit.getName());
	}
	public int getItemCount()
	{
		return mFruitList.size();
	}
}
重写onCreateHolder():创建Holder,并把布局加载到构造函数中,再把viewHolder返回;
        onBindViewHolder():对子项数据进行赋值,并在子项被滚入屏幕内执行,position获得当前实例
        getItemCount:RecyclerView子项的数目。

适配器准备好以后可以使用RecyclerView,修改MainActivity的代码

 public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<>();
    private FruitAdapter fruitAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.activity_main);
        initData();
        fruitAdapter = new FruitAdapter(fruitList);
        RecyclerView recyclerView = findViewById(R.id.recyclerview);
        //默认为垂直方向
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(fruitAdapter);
    }
    public void initData() {
        for (int i = 0; i < 2; 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);
            Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }
}
         

实现横向滚动和瀑布流布局

首先对fruit_item布局进行修改目前是水平排列,实现横向滚动竖直布局更加合理

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/image"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_gravity="center_horizontal">
    </ImageView>
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp">
    </TextView>
</LinearLayout>

然后修改MainActivity

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.activity_main);
        initData();
        FruitAdapter fruitAdapter = new FruitAdapter(fruitList);
        RecyclerView recyclerView = findViewById(R.id.recycler_h);
        //设置方向水平  LinearLayoutManager.HORIZONTAL
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        
        recyclerView.setAdapter(fruitAdapter);
        recyclerView.setLayoutManager(layoutManager);
    }
LIstView不能实现水平滑动的原因:

ListView的布局排列是由自身去管理的
RecyclerView的布局排列是由LayoutManager去控制,LayoutManager中制定了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能定制出各种不同排列方式的布局。
RecycleView还提供给我们GridLayoutManager和StaggeredGridLayoutManager这两种内置的布局排列方式。前者实现网格布局后者实现瀑布流布局

瀑布流布局

除了LinearLayoutManager之外,RecyclerView还提供了GridLayoutManager和StaggerdGridLayoutManager这两种内置的布局排列方式。
● GridLayoutManager可以用于实现网格布局,
● StaggerdGridLayoutManager可以用于实现瀑布流布局。

  1. 修改fruit_item.xml文件
    因为要实现瀑布流效果,所以需要对上面的fruit_item.xml文件进行修改:
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp">

    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginTop="10dp"/>

</LinearLayout>
  1. 使用StaggerdGridLayoutManager
public class MainActivity extends AppCompatActivity {

    private List<Fruit> mFruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(mFruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit(getRandomLengthName("Apple"), R.drawable.apple_pic);
            mFruitList.add(apple);
            Fruit banana = new Fruit(getRandomLengthName("Banana"), R.drawable.banana_pic);
            mFruitList.add(banana);
            Fruit orange = new Fruit(getRandomLengthName("Orange"), R.drawable.orange_pic);
            mFruitList.add(orange);
            Fruit watermelon = new Fruit(getRandomLengthName("Watermelon"), R.drawable.watermelon_pic);
            mFruitList.add(watermelon);
            Fruit pear = new Fruit(getRandomLengthName("Pear"), R.drawable.pear_pic);
            mFruitList.add(pear);
            Fruit grape = new Fruit(getRandomLengthName("Grape"), R.drawable.grape_pic);
            mFruitList.add(grape);
            Fruit pineapple = new Fruit(getRandomLengthName("Pineapple"), R.drawable.pineapple_pic);
            mFruitList.add(pineapple);
            Fruit strawberry = new Fruit(getRandomLengthName("Strawberry"), R.drawable.strawberry_pic);
            mFruitList.add(strawberry);
            Fruit cherry = new Fruit(getRandomLengthName("Cherry"), R.drawable.cherry_pic);
            mFruitList.add(cherry);
            Fruit mango = new Fruit(getRandomLengthName("Mango"), R.drawable.mango_pic);
            mFruitList.add(mango);
        }
    }
    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();
    }
}

StaggeredGridLayoutManager的构造函数接受两个参数,参数一:用于指定布局的列数,传入3表示会把布局分为3列;参数二用于指定布局的排列方向。

RecyclerView的点击事件

·RecyclerView并没有提供类似于setOnItemClickListener()这样的注册监听器方法,而是需要我们自己给子项具体的View去注册点击事件。
其实ListView的setOnItemClickListener()方法注册的是子项的点击事件,如果想点击子项里面具体的某一个按钮,ListView实现起来就有点复杂。为此,RecyclerView干脆直接摒弃了子项点击事件的监听器,所有的点击事件都由具体的View去注册。

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private List<Fruit> mFruitList;

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    //创建ViewHolder实例
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        //给子项最外层布局注册点击事件
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(), "you clicked view " + fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        //给子项中的ImageView注册点击事件
        holder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(), "you clicked image " + fruit.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    //对RecyclerView子项的数据进行赋值
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    //RecyclerView有多少子项
    @Override
    public int getItemCount() {
        return mFruitList.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView fruitImage;
        TextView fruitName;
        View fruitView; //子项最外层布局实例
        public ViewHolder(View itemView) {
            super(itemView);
            fruitView = itemView;
            fruitImage = ((ImageView) itemView.findViewById(R.id.fruit_image));
            fruitName = ((TextView) itemView.findViewById(R.id.fruit_name));
        }
    }
}

感谢观看

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值