RecyclerView是5.0新特性,是google为了替代ListView GridView这些组件,有自己的优点:耦合度很低的插件式组件;自己实现了convertView的重用,节省内存以及显示的速度
因为是5.0新特性,需要添加依赖
我就直接在代码里讲解了,代码注解很详细,可以看懂的
先看MaiActivity类:
package com.example.acer.wang_xue_gang_2016_6_5;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<String> data;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一步:获取控件
RecyclerView rl_RecylerView = (RecyclerView) findViewById(R.id.rl);
//第二步:初始化数据
initData();
//第三部:设置适配器
myAdapter = new MyAdapter(this, data);
rl_RecylerView.setAdapter(myAdapter);
//第四部:设置布局管理器,与ListView不同的地方——————线性布局管理器,垂直/水平grid布局管理器
//设置线性布局管理器
rl_RecylerView.setLayoutManager(new LinearLayoutManager(this));
//第五步:添加分割线
rl_RecylerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
}
public void initData() {
data = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
data.add("张欣爱我" + i + "生" + i + "世");
}
}
}
自定义的适配器
package com.example.acer.wang_xue_gang_2016_6_5;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
/**
* @author w_x_g
* @time 2016/6/5 16:38
* @note ${TODO}
*/
//泛型参事需要在类中定义
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
private LayoutInflater layoutInflater;
private List<String> listData;
public MyAdapter(Context context, List<String> listData) {
this.context = context;
this.layoutInflater = LayoutInflater.from(context);
this.listData = listData;
}
//创建ViewHolder缓存对象,将adapter_item布局渲染成view对象
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.adapter_item, parent, false);
//返回值是内部类,需要一个View 的参数,该参数就是条目的view对象
//把渲染的xml布局 交给MyViewHolder就实现了缓存,可以重复利用了
return new MyViewHolder(view);
}
//将数据与view 绑定
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv_item_textview.setText(listData.get(position));
}
@Override
public int getItemCount() {
return listData.size();
}
//在这里实现了缓存,
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv_item_textview;
public MyViewHolder(View itemView) {
super(itemView);
//拿到布局的控件,绑定数据的时候需要使用
tv_item_textview = (TextView) itemView.findViewById(R.id.tv_item);
}
}
}
activity_main.xml文件和adapter_item.xml文件
<?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:orientation="vertical"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#123456"
android:text="张欣"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
<?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:orientation="vertical">
<TextView
android:id="@+id/tv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="赵云"
/>
</LinearLayout>
大家敲一遍代码会发现,他和我们前面讲的listview的优化有很多相似之处!
看下运行效果
大家会发现recylerview没有分割线,RecyclerView并没有divider这样的属性!要想设置分割线需要重新抽象类RecyclerView.ItemDecoration;android文档中有一个官方demo;我们可以借用一下。
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/*
这个是v7 中的一个sample中的
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration{
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
//获取listDivider属性,该属性可在sdk\platforms\android-23\data\res\values中找到
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);//系统属性中获取
//改成自己的图片
//mDivider=context.getResource.getDrawable();
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override //在RecyclerView的onDraw中执行
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
/**
* 绘制纵向列表时的分隔线 这时分隔线是横着的
* 每次 left相同,top根据child变化,right相同,bottom也变化
* @param c
* @param parent
*/
public void drawVertical(Canvas c, RecyclerView parent) {
//左内边距,条目的起始点。
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
//根据不同的item设置不同的分割线
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
/**
* 绘制横向列表时的分隔线 这时分隔线是竖着的
* l、r 变化; t、b 不变
* @param c
* @param parent
*/
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override //预留item间隙 RecyclerView各个item之间默认是没有间隙的,但是绘制分割线却需要间隙,默认情况下高度等于分//割//线图片的高度
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
//获取图片物理尺寸的高度
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
//获取图片的实际宽度
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
然后我们在MainActivity里折折分割线
//第五步:添加分割线
rl_RecylerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
}
看下效果
这样我们就有分割线了,但是我们也可以使用自己的图片做分割线,我们修改下 DividerItemDecoration的构造方法;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
// mDivider = a.getDrawable(0);//系统属性中获取,可以在这里修改分割线图片
mDivider = context.getResources().getDrawable(R.mipmap.ic_launcher);
a.recycle();
setOrientation(orientation);
}
我们就是用系统自带的ic_launcher图片做分割线;看下效果
虽然分割线很丑,但好歹是我们自己的分割下了!
我们先定义一个R.drawable.divider_background文件
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<size
android:width="5dp"
android:height="5dp"/>
<gradient
android:centerColor="#00ff00"
android:endColor="#0000ff"
android:startColor="#ff0000"/>
</shape>
修改res\values\styles.xml文件:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!--自己定义listDivider,覆盖系统定义的-->
<item name="android:listDivider">@drawable/divider_background</item>
</style>
</resources>
使用自己定义的,覆盖系统自己定义的,我们看下运行效果