Android UI控件之ListView&RecyclerView

来源:互联网 发布:高中地理优化设计 编辑:程序博客网 时间:2024/06/05 02:53

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()中的代码进行一次小的修改。如下:

@Overridepublic 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。代码如下:

@Overridepublic 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要好一些。

0 0
原创粉丝点击