RecyclerView的最简单用法
关于RView,首先是其基本的用法,要让它运行起来需要处理哪些块的东西,下面将详细讲解,这个例子简化了grokkingandroid的例子A First Glance at Android’s RecyclerView。
1 引入v7包,注意这里的+号尽量写成某一个版本而不用+号,其版本号可以在网上查询得到。
compile 'com.android.support:recyclerview-v7:+'
compile 'com.android.support:cardview-v7:+'
2 XML里的基础设置
<RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rview"
/>
这里需要注意的是listview的divider相关属性已经没有了。而关于分割线需要自己写,后面会讲到。
当然肯定不会少item得布局设置:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container_inner_item"
android:layout_width="200dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="8dp"
android:layout_centerVertical="true"
>
<TextView
android:id="@+id/txt_label_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
tools:text="Item Number One" />
<TextView
android:id="@+id/txt_date_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
tools:text="Item Number One" />
</LinearLayout>
3 在Activity里面,引入RecyclerView之后需要处理两个模块,分别如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.rview);
recyclerView.setLayoutManager(getLayoutManager());
getData();
getAdapter();
recyclerView.setAdapter(adapter);
}
获取LayoutManager,获取适配器Adapter。与以前ListView的主要不同就在于RecyclerView多了一个LayoutManager,关于它后面会细讲,下面是这几个获取方法:
private void getAdapter() {
adapter = new RViewAdapter();
}
private void getData() {
demoData = new ArrayList<>();
for (int i = 0; i < 20; i++) {
DemoModel model = new DemoModel();
model.label = "Test Label No. " + i;
model.dateTime = "Test Label No. " + i;
demoData.add(model);
}
}
public LinearLayoutManager getLayoutManager() {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
// actually VERTICAL is the default,
// just remember: LinearLayoutManager
// supports HORIZONTAL layout out of the box
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
// you can set the first visible item like this:
layoutManager.scrollToPosition(0);
return layoutManager;
}
class RViewAdapter extends RecyclerView.Adapter<ListItemViewHolder>{
@Override public ListItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.
from(getApplicationContext()).
inflate(R.layout.common_item_layout, viewGroup, false);
return new ListItemViewHolder(itemView);
}
@Override public void onBindViewHolder(ListItemViewHolder listItemViewHolder, int position) {
DemoModel model = demoData.get(position);
listItemViewHolder.label.setText(model.label);
listItemViewHolder.dateTime.setText(model.dateTime);
}
@Override public int getItemCount() {
return demoData.size();
}
}
public final static class ListItemViewHolder extends RecyclerView.ViewHolder {
TextView label;
TextView dateTime;
public ListItemViewHolder(View itemView) {
super(itemView);
label = (TextView) itemView.findViewById(R.id.txt_label_item);
dateTime = (TextView) itemView.findViewById(R.id.txt_date_time);
}
}
对比以前ListView的写法,将ViewHolder放在Tag里面利于重用的写法已经普及开来,因此官方注意到这个类,将其与适配器结合进行了重构和优化。
大功告成。
以上就是RView的基本用法了,没有其他任何的多余代码,每个步骤都是必须的。下面我们来对这个RView进行提问并逐个解决好让它更加贴近我们的项目。
1 关于XML里面的RView的设置。
android:dividerHeight 和 android:divider两个属性在RView里是没有的,唯一的办法就是重写RecyclerView.ItemDecoration,从名字上看是某项的修饰的意思,因此要想实现分割线及其高度需要自己写代码,幸运的是在V7包下的例子中可以找到DividerItemDecoration这个类,它实现了分割线,网上的众多版本基本都是从此而来,下面贴代码:
package com.grokkingandroid.samplesapp.samples.recyclerviewdemo;
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.util.Log;
import android.view.View;
/**
* This class is from the v7 samples of the Android SDK. It's not by me!
* <p/>
* See the license above for details.
*/
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) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
Log.v("recyclerview - itemdecoration", "onDraw()");
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
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);
}
}
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
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);
}
}
}
可以看到分割线都是依靠onDraw方法绘制上去的,而垂直和水平的分割线是通过绘制的时候取上下左右的位置不同而决定的。
当然,还需在RView里面进行设置:
RecyclerView.ItemDecoration itemDecoration =
new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);
android:listSelector属性在RView里面也是没有的,因此点击Item的效果就不能在RView里设置了,解决办法是写在item布局的顶Layout的background属性里,但必须加上android:clickable属性,当item的子view还有其他点击效果时需加上android:duplicateParentState属性:
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container_inner_item"
android:layout_width="200dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="8dp"
android:layout_centerVertical="true"
android:clickable="true"
android:background="@drawable/statelist_item_background"
>
下次将继续对RView进行提问并解答,层层递进对其进行扩展。