1. 程式人生 > >RecyclerView的基本用法 (一)

RecyclerView的基本用法 (一)

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;
  }
4 介面卡的內容也與以前ListView的內容大為不同,主要體現在ViewHolder上:
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進行提問並解答,層層遞進對其進行擴充套件。