zoukankan      html  css  js  c++  java
  • 12.Android开发笔记:RecyclerView

    0.准备工作

    RecyclerView是一个滚动控件,
    想要使用RecyclerView这个控件,需要将 v7 支持库添加到项目中,
    recyclerview 官方文档

    首先需要在项目的build.gradle中添加相应的依赖库才行。
    打开app/build.gradle文件,在dependencies闭包中添加如下内容:

         implementation 'com.android.support:recyclerview-v7:28.0.0'
    

    gradle文件自上次同步之后又发生了变化,需要再次同步才能使项目正常工作。这里只需要点击Sync Now就可以了,然后gradle会开始进行同步。

    1.简单用法

    (1).修改 activity_main.xml

    
    <?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"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
    <!--   
       官网示例,运行出错
       <android.support.v7.widget.RecyclerView
            android:id="@+id/my_recycler_view"
            android:scrollbars="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    -->
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/my_recycler_view"
            android:scrollbars="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </LinearLayout>
    
    

    (2).创建Fruit

    public class Fruit {
    
        private String name;
        private int imageId;
    
        public Fruit(int imageId, String name){
            this.name = name;
            this.imageId = imageId;
    
        }
    
        public String getName() {
            return name;
        }
    
        public int getImageId() {
            return imageId;
        }
    }
    
    
    

    (3)创建Adapter

    1).FruitAdapter 继承 RecyclerView.Adapter<FruitViewHolder>
    2).FruitViewHolder是自定义内部类
    3).要实现三个接口:
    onCreateViewHolder, onBindViewHolder ,getItemCount

    
    public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.FruitViewHolder> {
    
        private List<Fruit> fruits;
    
        static class FruitViewHolder extends RecyclerView.ViewHolder{
    
            ImageView fruitImage;
            TextView fruitName;
    
            /**
             * ViewHolder的构造函数中要传入一个View参数,
             * 这个参数通常就是RecyclerView子项的最外层布局,
             * 那么我们就可以通过findViewById()方法来获取到布局中的ImageView和TextView的实例
             * */
            public FruitViewHolder(@NonNull View itemView) {
                super(itemView);
                fruitImage = itemView.findViewById(R.id.fruit_image);
                fruitName = itemView.findViewById(R.id.fruit_name);
    
            }
        }
    
        public FruitAdapter(List<Fruit> fruits) {
            this.fruits = fruits;
        }
    
        @NonNull
        @Override
        public FruitViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.fruit_item, parent, false);
            FruitViewHolder holder = new FruitViewHolder(view);
    
            return  holder;
        }
    
        /**
         *用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行
         * */
        @Override
        public void onBindViewHolder(@NonNull FruitViewHolder holder, int position) {
            Fruit fruit = fruits.get(position);
    
            holder.fruitImage.setImageResource(fruit.getImageId());
            holder.fruitName.setText(fruit.getName());
        }
    
        @Override
        public int getItemCount() {
            return fruits.size();
        }
    
    }
    
    
    

    (4)绑定数据

    
    public class MainActivity extends AppCompatActivity {
    
        private List<Fruit> fruits = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            InitFruits();
    
            RecyclerView recyclerView = findViewById(R.id.my_recycler_view);
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
            recyclerView.setLayoutManager(linearLayoutManager);
            FruitAdapter fruitAdapter = new FruitAdapter(fruits);
            recyclerView.setAdapter(fruitAdapter);
        }
    
        private  void InitFruits(){
    
            for (int i= 0; i < 10 ; i++){
                Fruit taozi = new Fruit(R.drawable.taozi, "桃子");
                fruits.add(taozi);
    
                Fruit putao = new Fruit(R.drawable.putao, "葡萄");
                fruits.add(putao);
    
                Fruit huolongguo = new Fruit(R.drawable.huolongguo, "火龙果");
                fruits.add(huolongguo);
    
                Fruit lamei = new Fruit(R.drawable.lanmei, "蓝莓");
                fruits.add(lamei);
    
                Fruit xiguang = new Fruit(R.drawable.xigua, "西瓜");
                fruits.add(xiguang);
            }
        }
    }
    
    
    

    效果:

    把图片放在res/drawable文件夹,启动App时,可能出现的bug:

        ...
        java.lang.RuntimeException: Canvas: trying to draw too large(110250000bytes) bitmap.
        ...
    

    参见:解决方案

    新建 drawable-nodpi 文件夹把图片移动到该文件夹即可。

    2 实现横向滚动

    1).修改fruit_item.xml 布局:
    图片和文字垂直排列: android:orientation="vertical"
    调整每个Fruit宽度: android:layout_width="wrap_content"

    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    
        <ImageView android:id="@+id/fruit_image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical"/>
        <TextView android:id="@+id/fruit_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"/>
    </LinearLayout> 
    
    

    2)修改滚动方向:

      ...
      linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
      ...
    
    

    3.瀑布流布局

    ListView的布局排列是由自身去管理的,
    RecyclerView则将这个工作交给了LayoutManager,
    LayoutManager中制定了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能定制出各种不同排列方式的布局了。
    除了LinearLayoutManager之外,
    RecyclerView还给我们提供了GridLayoutManagerStaggeredGridLayoutManager这两种内置的布局排列方式。
    GridLayoutManager可以用于实现网格布局,
    StaggeredGridLayoutManager可以用于实现瀑布流布局。

    1)修改fruit_item.xml 布局:
    修改宽度: android:layout_width="120dp"

    
    <!--瀑布流布局-->
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    
        <ImageView android:id="@+id/fruit_image"
            android:layout_width="120dp"
            android:layout_height="100dp"
            android:layout_gravity="center_vertical"/>
        <TextView android:id="@+id/fruit_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"/>
    </LinearLayout>
    
    

    2)使用瀑布流布局

    
            RecyclerView recyclerView = findViewById(R.id.my_recycler_view);
    
           /*
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
            linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); //横向布局
            recyclerView.setLayoutManager(linearLayoutManager);
            */
    
            //瀑布流布局:其中参数StaggeredGridLayoutManager.VERTICAL表示 从左往右依次排开,满行另起一行
            StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(6, StaggeredGridLayoutManager.VERTICAL);
            recyclerView.setLayoutManager(layoutManager);
    
            FruitAdapter fruitAdapter = new FruitAdapter(fruits);
            recyclerView.setAdapter(fruitAdapter);
    
    

    4.RecyclerView的点击事件

    不过不同于ListView的是,RecyclerView并没有提供类似于setOnItemClickListener()这样的注册监听器方法,而是需要我们自己给子项具体的View去注册点击事件,
    ListView在点击事件上的处理并不人性化,setOnItemClickListener()方法注册的是子项的点击事件,但如果我想点击的是子项里具体的某一个按钮呢?虽然ListView也是能做到的,但是实现起来就相对比较麻烦了。
    为此,RecyclerView干脆直接摒弃了子项点击事件的监听器,所有的点击事件都由具体的View去注册,就再没有这个困扰了。

    1)FruitViewHolder
    新增变量 View fruitView; 用于保存子项的最外层布局的实例

    
        static class FruitViewHolder extends RecyclerView.ViewHolder{
            View fruitView; //子项的最外层布局的实例
            ImageView fruitImage;
            TextView fruitName;
    
            /**
             * ViewHolder的构造函数中要传入一个View参数,
             * 这个参数通常就是RecyclerView子项的最外层布局,
             * 那么我们就可以通过findViewById()方法来获取到布局中的ImageView和TextView的实例
             * */
            public FruitViewHolder(@NonNull View itemView) {
                super(itemView);
    
                fruitView = itemView; //子项的最外层布局的实例
                fruitImage = itemView.findViewById(R.id.fruit_image);
                fruitName = itemView.findViewById(R.id.fruit_name);
    
            }
        }
    
    
    1. FruitAdapter
      在方法onCreateViewHolder中注册点击事件
    @NonNull
        @Override
        public FruitViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.fruit_item, parent, false);
            final FruitViewHolder holder = new FruitViewHolder(view);
    
            //为子项的最外层布局注册点击事件:
            holder.fruitView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getAdapterPosition();
                    Fruit fruit = fruits.get(position);
                    Toast.makeText( v.getContext(), "点击子项View:"+ fruit.getName(), Toast.LENGTH_SHORT).show();
                }
            });
    
            //为子项的图片注册点击事件:
            holder.fruitImage.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getAdapterPosition();
                    Fruit fruit = fruits.get(position);
                    Toast.makeText(v.getContext(), "点击子项View中的ImageView:"+ fruit.getName(), Toast.LENGTH_SHORT).show();
                }
            });
    
            return  holder;
        }
    
    

    点击图片

    点击文字,文字没有注册点击事件,最终会被最外层布局捕获

  • 相关阅读:
    金蝶VB插件开发,单据不满足条件,拒绝保存
    继承(子类构造执行的过程)
    Javascript基础(一)
    异常处理(一)
    File I/O(三)
    图片轮播
    java中的foreach循环
    File I/O(一)
    集合框架(三)
    集合框架(二)
  • 原文地址:https://www.cnblogs.com/easy5weikai/p/12518238.html
Copyright © 2011-2022 走看看