2、Android-UI(RecyclerView)

2.6、滚动控件-RecylerView

ListView虽然使用的效果很好但是也是有缺点的

不使用一些技巧来提升它的运行效率,性能就非常差

扩展性也不是很好

只能实现数据的纵向滚动效果

实现横向滚动是做不到的

 

Android提供一个更强大的滚动控件---RecylerView

是一个增强版的ListView

不仅可以轻松实现和ListView同样效果

还优化了ListView中 存在的不足之处

 

目前官方更推荐使用RecyclerView

未来会有更多的程序主键从ListView转向RecyclerView

 

1、基本用法

首先再app/build.gradle文件中引入:

   compile 'com.android.support:recyclerview-v7:23.4.0'

 

再first_activity中:

<?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.support.v7.widget.RecyclerView
        android:id="@+id/recyler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
       
</LinearLayout>

 

新建一个适配类

继承RecyclerView.Adapter,并且将泛型指定为内部类ViewHolder

public class FruitAdaperRecyler extends RecyclerView.Adapter<FruitAdaperRecyler.ViewHolder> {
    private List<Fruit> fruitList;

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,null,false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = fruitList.get(position);
        holder.textView.setText(fruit.getName());
       holder.imageView.setImageResource(fruit.getId());

    }
    @Override
    public int getItemCount() {
        return fruitList.size();
    }

     //自定义的内部类
      class ViewHolder extends RecyclerView.ViewHolder{
        //布局文件中的两个控件
        ImageView imageView;
        TextView textView;
        public ViewHolder(View itemView) {
            super(itemView);
            imageView  = (ImageView) itemView.findViewById(R.id.image_view);
            textView = (TextView) itemView.findViewById(R.id.text_view);
        }
    }

    //构造器
    public FruitAdaperRecyler(List<Fruit> fruits){
        this.fruitList = fruits;
    }
}

 

首先定义一个内部类ViewHolder

需要继承RecyclerHolder

然后再构造参数中要传入一个view参数

这个参数通常就是RecyclerView子项的最外层布局

那么就可以通过findViewById()方法获取到布局中的ImageView和TextView的实例

 

FruitAdaperRecyler类中有一个构造函数就是将要展示的数据传进来

并且复制给一个全局变量,后续的操作都是在全局变量的基础上进行的

 

FruitAdaperRecyler继承RecyclerView.Adapter就需要实现其中的三个方法

1、omCreateViewHolder()方法就是用于创建viewholder的实例,再方法中将fruit_item布局加载进来

  然后创建一个viewHolder实例,并把加载出来的布局传入传入到构造函数中

  最后将viewHolder的实例返回

2、onBinbViewHolder()方法用于对Recycler子项的数据进行赋值,会在每一个子项被滚动到屏幕内时执行

  这里通过position参数可以获得到当前的Fruit的实例,然后进行设置id和name

3、getItemCount()就是返回REcyclerView一共有多少个子项,直接返回数据源的长度即可

 

mainAcctivity中的代码:

public class MainActivity extends AppCompatActivity {
    private List<Fruit> fruitList = new ArrayList<>();

    private void initFruit(){
            Fruit apple = new Fruit("Apple1",R.drawable.qq);
            fruitList.add(apple);
            Fruit apple1 = new Fruit("Apple2",R.drawable.qq);
            fruitList.add(apple1);
            Fruit apple2 = new Fruit("Apple3",R.drawable.qq);
            fruitList.add(apple2);
            Fruit apple3 = new Fruit("Apple4",R.drawable.qq);
            fruitList.add(apple3);
            Fruit apple4 = new Fruit("Apple5",R.drawable.qq);
            fruitList.add(apple4);
            Fruit apple5 = new Fruit("Apple6",R.drawable.qq);
            fruitList.add(apple5);
            Fruit apple6 = new Fruit("Apple7",R.drawable.qq);
            fruitList.add(apple6);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.firstlayout);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.hide();
        }
        //初始化
        initFruit();

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyler_view);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        FruitAdaperRecyler fruitAdaperRecyler = new FruitAdaperRecyler(fruitList);

        recyclerView.setAdapter(fruitAdaperRecyler);
    }
}

使用initFruit进行初始化数据

再onCreate()方法中首先获取RecyclerView的实例

然后创建一个LinearLayoutManager对象,在这里是线性布局的意思

再进行创建FruitAdapterRecyler的实例

并且将水果的数据传入

醉胡调用RecyclerView的setAdapter()方法来完成适配器的设置

此时RecyrView和数据之间的关联建立完成

实现了和ListView几乎一样的效果

再实现的过程中逻辑清晰

 

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

文件中的布局元素都是水平排列的

适用于纵向滚动的场景

 

 实现横向滚动则需要改成垂直排列

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="match_parent">

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

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

</LinearLayout>

 

将LinerLayout改成垂直方向的排列

此时设置的宽度时100dp

将宽度指定为固定的值可以有效的包裹文字,防止其过长或者过短的美观问题

 

进行修改代码:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.firstlayout);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.hide();
        }
        //初始化
        initFruit();

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyler_view);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

        recyclerView.setLayoutManager(linearLayoutManager);
        FruitAdaperRecyler fruitAdaperRecyler = new FruitAdaperRecyler(fruitList);

        recyclerView.setAdapter(fruitAdaperRecyler);
    }

 

 之加入了一行代码

调用LinearLayoutManager的setOrientation()方法来设置不久排列的排列方向

此时的设置表示横向排列

默认是纵向排列

 

 

 处LInearLayoutManager之外

还提供了GridLayoutManagerStaggeredGridLayoutManager这两种内置的布局排列方式

前者可以实现网格布局

后者可以实现瀑布流布局

 

 

<?xml version="1.0" encoding="utf-8"?>
<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/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"

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

</LinearLayout>

 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.firstlayout);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.hide();
        }
        //初始化
        initFruit();

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyler_view);

        StaggeredGridLayoutManager staggeredGridLayoutManager =  new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);
        FruitAdaperRecyler fruitAdaperRecyler = new FruitAdaperRecyler(fruitList);
        recyclerView.setAdapter(fruitAdaperRecyler);
    }
StaggeredGridLayoutManager staggeredGridLayoutManager =  new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);

第一个参数用于指定列数

第二个参数用于指定布局的排列方向

 

 

 

 结果展示:

 

3、点击事件:

所有的点击事件都有具体的View去注册

代码如下: 

public class FruitAdaperRecyler extends RecyclerView.Adapter<FruitAdaperRecyler.ViewHolder> {
    private List<Fruit> fruitList;

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,null,false);
        final ViewHolder viewHolder = new ViewHolder(view);

        //点击事件的监听
        viewHolder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = viewHolder.getAdapterPosition();
                Fruit fruit = fruitList.get(position);
                Toast.makeText(v.getContext(),"clicked:"+fruit.getName(),Toast.LENGTH_LONG).show();
            }
        });
        viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = viewHolder.getAdapterPosition();
                Fruit fruit = fruitList.get(position);
                Toast.makeText(v.getContext(),"click image :" + fruit.getName(),Toast.LENGTH_LONG).show();
            }
        });

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = fruitList.get(position);
        holder.textView.setText(fruit.getName());
       holder.imageView.setImageResource(fruit.getId());

    }

    @Override
    public int getItemCount() {
        return fruitList.size();
    }


     //自定义的内部类
      class ViewHolder extends RecyclerView.ViewHolder{
        //布局文件中的两个控件
        ImageView imageView;
        TextView textView;
         View fruitView;

        public ViewHolder(View itemView) {
            super(itemView);
            fruitView=itemView;
            imageView  = (ImageView) itemView.findViewById(R.id.image_view);
            textView = (TextView) itemView.findViewById(R.id.text_view);
        }
    }

    //构造器
    public FruitAdaperRecyler(List<Fruit> fruits){
        this.fruitList = fruits;
    }
}

 

首先是在ViewHolder中添加了fruitView变量来保存子项最外层的布局实例

然后再onCreateViewHolder()方法中注册点击事件

首先是获取用户点击的position

然后通过position获取用户拿到享用的Fruit实例

最后将内容进行显示

点击文字和图片都可以正常的进行打印显示的信息

 

posted @ 2019-04-09 09:09  MrChengs  阅读(262)  评论(0编辑  收藏  举报