Android UI控件之ListView&RecyclerView

Android UI控件之ListView&RecyclerView


前言

ListView&RecyclerView 这次我们来说说这两个控件的区别,我们知道ListView在有限的屏幕上显示更多的内容,若不使用优化的方案会导致性能很差,现在出现了RecyclerView滚动控件,同样可以实现listView的功能还可以解决listView存在的问题。

两者虽然功能很强大但是创建起来比起普通的控件多少有些麻烦,而创建之中要属适配器的定制是最麻烦的。适配器:是一个连接数据和AdapterView(ListView就是一个典型的AdapterView)的桥梁,通过它能有效实现数据与AdapterView的分离设置,使AdapterView和数据的绑定简便,修改更加方便。搞定适配器基本就了解这两个控件是怎么玩的了。

ListView

我们先来看ListView的创建过程,ListView的子项中显示什么需要定义一个实体类,作为ListView适配器的适配类型,
如:

public class Fruit {

        private String name;

        private int imageId;

        public Fruit(String name, int imageId) {
            this.name = name;
            this.imageId = imageId;
        }
    // Getter()
    ……
    }

再创建ListView子项的自定义布局文件。在展示ListView的布局中使用的标签

public class FruitAdapter extends ArrayAdapter<Fruit> {

        private int resourceId;
    //这个构造函数传入的参数分别是:上下文、ListView子项布局的id、数据
        public FruitAdapter(Context context, int textViewResourceId,List<Fruit> objects) {
            super(context, textViewResourceId, objects);
            resourceId = textViewResourceId;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Fruit fruit = getItem(position); // 获取当前项的Fruit实例
            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;
        }
    }

下面将数据借助适配器加载到ListView控件中显示

FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);

可是这样的适配器是比较难用的,每次快速滚动ListView的时候,getView()中每次都要将布局重新加载一遍,影响性能。每次都要重新加载布局,想想都觉得会拖慢速度,怎么办?所以把getView()中的代码进行一次小的修改。如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
            Fruit fruit = getItem(position); // 获取当前项的Fruit实例
            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是否为null,为null就用LayoutInflater重新加载布局,否则直接重用。这样是解决了布局的重复加载的问题,可是控件还是要重新调用,所以还要进一步优化,这时候就要用到ViewHolder。代码如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
            Fruit fruit = getItem(position); // 获取当前项的Fruit实例
            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); // 将ViewHolder存储在View中
            } else {
                view = convertView;
                viewHolder = (ViewHolder) view.getTag(); // 重新获取ViewHolder
            }
            viewHolder.fruitImage.setImageResource(fruit.getImageId());
            viewHolder.fruitName.setText(fruit.getName());
            return view;
        }

        class ViewHolder {

            ImageView fruitImage;

            TextView fruitName;

        }

上一次的优化是加入了convertView且进行判断,是对子项布局缓存并重用,这个是在自定义适配器类中定义了ViewHolder类并声明了子项中得控件。在填充了子项布局后实例化控件,view.setTag(viewHolder)将ViewHolder缓存在View中。 view.getTag()将ViewHolder重新取出,经过这两次优化会很好的提高性能,其中我们也叫能看清ListView实现的过程。

RecyclerView

接下来我们继续来介绍RecyclerView滚动控件,RecyclerView定义在support库中所以需要在build.gradle中添加依赖库

dependencies{
        .....
        compile 'com.android.support:recyclerview-v7:24.2.1'

    }

布局中添加RecyclerView控件

<android.support.v7.widget.RecyclerView
      android:id="@+id/recycler_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />

RecyclerView控件很强大,不但能实现listView的功能,在滚动方向上可以横向滑动。
下面来介绍RecyclerView控件适配器类的创建,以便和ListView做个对比,这个仍然要定义一个实体类作为适配器的适配类型。
代码如下:

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

        private List<Fruit> mFruitList;

        static class ViewHolder extends RecyclerView.ViewHolder {
            ImageView fruitImage;
            TextView fruitName;

            public ViewHolder(View view) {
                super(view);
                fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
                fruitName = (TextView) view.findViewById(R.id.fruit_name);
            }
        }

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

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);//recyclerView这里就添加子项布局,而listView在真正适配的时候用到子项布局
            ViewHolder holder = new ViewHolder(view);
            return holder;
        }

        @Override
        public void onBindViewHolder(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();
        }

    }

我们看到这个适配器继承了RecyclerView.Adapter,并指定FruitAdapter.ViewHolder泛型类型,这里也写一个内部类ViewHolder,和ListView适配器中很像,但这个除了声明了控件,还获得了控件的实例,这样控件直接封装到这个ViewHolder里。
这个内部类往下,有一个构造函数用来传入数据。剩下的是重写的三个方法:onCreateViewHolder()、onBindViewHolder()和getItemCount()。
- onCreateViewHolder():中用来创建ViewHolder实例和加载子项布局
- onBindViewHolder():通过获得子项的位置position,对RecyclerView每个子项进行赋值添加数据。
- getItemCount():返回子项的长度

看一下如何使用这个适配器:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    LinearLayoutManager layoutManager = new LinearLayoutManger(this);
    //对线性布局设置排列的方向,默认是纵向,这个是设置成了横向排列
    //layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
    recyclerView.setLayoutManager(layoutManager);
    FruitAdapter adapter = new FruitAdapter(fruitList);
    recyclerView.setAdapter(adapter);

这里我们可以看到RecyclerView除了绑定控件获得实例,通过适配器添加数据,还加入了对RecyclerView滚动控件布局形式的排列,不得不说这要比ListView在展现形式要灵活很多。
此外在事件触发的设计上两者也存在着差异,结果还是RecyclerView要好一些。

发布了30 篇原创文章 · 获赞 5 · 访问量 7676

猜你喜欢

转载自blog.csdn.net/c0586/article/details/61426584
今日推荐