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之外
还提供了GridLayoutManager、StaggeredGridLayoutManager这两种内置的布局排列方式
前者可以实现网格布局
后者可以实现瀑布流布局
<?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实例
最后将内容进行显示
点击文字和图片都可以正常的进行打印显示的信息