1. 程式人生 > >Android控制元件RecyclerView實現橫向滑動、瀑布流。

Android控制元件RecyclerView實現橫向滑動、瀑布流。

在開發的過程中,我們經常使用ListView控制元件,但是ListView也有它的缺點,就是它不能夠左右滑動資料,執行效率不高;
所以我們可以使用更強大的控制元件RecyclerView,可以說它是一個增強版的ListView,Google推薦使用,那就簡單的使用一下這個控制元件。

首先,我們先來實現一個跟ListView一樣效果的介面。

這裡寫圖片描述

因為RecyclerView是在support包中,所以我們要在build.gradle中新增該依賴。

compile 'com.android.support:recyclerview-v7:25.1.0'

第一步,在佈局中創建出該控制元件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context
="com.example.dell.recyclerviewdemo.MainActivity">
<android.support.v7.widget.RecyclerView android:id="@+id/recyc" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>

第二步,建立行佈局item

這裡寫圖片描述

<?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="wrap_content" android:orientation="horizontal" android:padding="10dp"> <ImageView android:id="@+id/item_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/item_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="20dp" android:text="Hello World!" /> </LinearLayout>

第三步:建立實體類,來封裝資料


/**
 * Created by Dell on 2017/1/9.
 */

public class ItemVO {
    private int mImg;
    private String mName;

    public ItemVO(int mImg, String mName) {
        this.mImg = mImg;
        this.mName = mName;
    }

    public void setmImg(int mImg) {
        this.mImg = mImg;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public int getmImg() {
        return mImg;
    }

    public String getmName() {
        return mName;
    }
}

第四步:建立介面卡

package com.example.adapter;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.dell.recyclerviewdemo.R;
import com.example.vo.ItemVO;

import java.util.List;

/**
 * Created by Dell on 2017/1/9.
 */

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
    //動態陣列
    private List<ItemVO> mList;

    //構造
    public MyAdapter(List<ItemVO> mList) {
        this.mList = mList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //繫結行佈局
        View view = View.inflate(parent.getContext(),R.layout.item,null);
        //例項化ViewHolder
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    //設定資料
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        //獲取當前實體類物件
        ItemVO vo = mList.get(position);
        //設定
        holder.text.setText(vo.getmName());
        holder.img.setImageResource(vo.getmImg());
    }

    //數量
    @Override
    public int getItemCount() {
        return mList.size();
    }

    //內部類
    class ViewHolder extends RecyclerView.ViewHolder{
        //行佈局中的控制元件
        ImageView img;
        TextView text;
        public ViewHolder(View itemView) {
            super(itemView);
            //繫結控制元件
            img = (ImageView) itemView.findViewById(R.id.item_img);
            text = (TextView) itemView.findViewById(R.id.item_text);
        }
    }
}
說明:

首先定義了一個內部類ViewHolder,繼承RecyclerView.ViewHolder,然後定義兩個兩個全域性變數,即行佈局中的控制元件,然後再構造方法中繫結控制元件。
然後將介面卡這個類繼承RecyclerView.Adapter<內部類>,需要重寫onCreateViewHolder()、onBindViewHolder()、getItemCount()這三個方法。
onCreateViewHolder():建立ViewHolder例項。
onBindViewHolder():對資料進行賦值。
getItemCount():返回有多少資料。

第五步:MainActivity

package com.example.dell.recyclerviewdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.example.adapter.MyAdapter;
import com.example.vo.ItemVO;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RecyclerView mView;
    private List<ItemVO> mList = new ArrayList<ItemVO>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //繫結id
        bindID();
        //新增資料
        addData();
        //建立LinearLayoutManager
        LinearLayoutManager manager = new LinearLayoutManager(this);
        //設定
        mView.setLayoutManager(manager);
        //例項化介面卡
        MyAdapter myAdapter = new MyAdapter(mList);
        //設定介面卡
        mView.setAdapter(myAdapter);
    }

    private void addData() {
        for (int i = 0 ; i<50 ; i++){
            ItemVO itemVO = new ItemVO(R.mipmap.ic_launcher, i + ":Hello World!");
            //新增到陣列
            mList.add(itemVO);
            itemVO = null;
        }
    }

    private void bindID() {
        mView = (RecyclerView) findViewById(R.id.recyc);
    }
}
說明:

這裡跟ListView的使用方式是差不多的。
使用一個addData()方法新增資料到mList,接著在onCreate()方法中首先獲取到RecyclerView例項,然後創建出一個LinearLayoutManager物件,將讓設定到RecyclerView當中。LinearLayoutManager用於指定RecyclerView的佈局方式;然後例項化MyAdapter;最後繫結介面卡。

這樣,效果跟ListView實現是一樣的。

改變滑動方向:橫向滑動

這裡寫圖片描述

首先改變一下行佈局item

因為是橫向滑動,所以我們將行佈局的寬度限定了。

<?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="100dp"
    android:orientation="vertical"
    android:padding="10dp">

    <ImageView
        android:id="@+id/item_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Hello World!" />
</LinearLayout>

修改MainActivity

在onCreate()中給LinearLayoutManager設定屬性


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //繫結id
        bindID();
        //新增資料
        addData();
        //建立LinearLayoutManager
        LinearLayoutManager manager = new LinearLayoutManager(this);
        //設定為橫向滑動
        manager.setOrientation(LinearLayoutManager.HORIZONTAL);
        //設定
        mView.setLayoutManager(manager);
        //例項化介面卡
        MyAdapter myAdapter = new MyAdapter(mList);
        //設定介面卡
        mView.setAdapter(myAdapter);
    }

執行後,就會實現這個橫向滑動了。
這樣,RecyclerView的優勢就顯示出來了,完成了ListVIew不能完成的任務。

使用RecyclerView實現瀑布流

這裡寫圖片描述

第一步:修改行佈局Item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5dp">

    <ImageView
        android:id="@+id/item_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Hello World!" />
</LinearLayout>

將行佈局寬度更改為自定義。

修改MainActivity

package com.example.dell.recyclerviewdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;

import com.example.adapter.MyAdapter;
import com.example.vo.ItemVO;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity {
    private RecyclerView mView;
    private List<ItemVO> mList = new ArrayList<ItemVO>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //繫結id
        bindID();
        //新增資料
        addData();
//        //建立LinearLayoutManager
//        LinearLayoutManager manager = new LinearLayoutManager(this);
//        //設定為橫向滑動
//        manager.setOrientation(LinearLayoutManager.HORIZONTAL);
        //引數意思:分為幾列;方向。
        StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);

        //設定
        mView.setLayoutManager(manager);
        //例項化介面卡
        MyAdapter myAdapter = new MyAdapter(mList);
        //設定介面卡
        mView.setAdapter(myAdapter);
    }

    private void addData() {
        for (int i = 0; i < 50; i++) {
            ItemVO itemVO = new ItemVO(R.mipmap.ic_launcher, getRandomStr(i + ":Hello World!"));
            //新增到陣列
            mList.add(itemVO);
            itemVO = null;
        }
    }
    //將文字長度改變
    private String getRandomStr(String str){
        Random random = new Random();
        int num = random.nextInt(10)+1;
        StringBuilder builder = new StringBuilder();
        for (int i = 0 ; i< num ;i++){
            builder.append(str+"");
        }
        return builder.toString();
    }

    private void bindID() {
        mView = (RecyclerView) findViewById(R.id.recyc);
    }
}

說明:

將關於LinearLayoutManager的都註釋掉,使用StaggeredGridLayoutManager物件。
因為瀑布流在textView資料長度不同的時候才能看到,所以我們就隨機更該文字的長度,讓瀑布流效果顯示出來。

RecyclerView實現點選事件的監聽

這裡寫圖片描述
在RecyclerView中,沒有提供給我們點選事件的方法,需要我們自己給子項具體的View去註冊點選事件,相比ListView,這的確是比較麻煩,但是不代表RecyclerView不好,而是RecyclerView是人性化設計,可以根據自己的需要去設計,我們可以給每一個item設定監聽,也可以給每一個TextView或其他設定監聽。

修改MyAdapter

給每個item 和 textView設定監聽

package com.example.adapter;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.dell.recyclerviewdemo.R;
import com.example.vo.ItemVO;

import java.util.List;

/**
 * Created by Dell on 2017/1/9.
 */

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
    //動態陣列
    private List<ItemVO> mList;

    //構造
    public MyAdapter(List<ItemVO> mList) {
        this.mList = mList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //繫結行佈局
        final View view = View.inflate(parent.getContext(),R.layout.item,null);
        //例項化ViewHolder
        final ViewHolder holder = new ViewHolder(view);
        //item設定監聽
        holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //獲取到position
                int layoutPosition = holder.getLayoutPosition();
                //土司
                Toast.makeText(view.getContext(),"This is item :"+layoutPosition,Toast.LENGTH_SHORT).show();
            }
        });
        //textView設定監聽
        holder.text.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //獲取到position
                int layoutPosition = holder.getLayoutPosition();
                //土司
                Toast.makeText(view.getContext(),"This is textView :"+layoutPosition,Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    //設定資料
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        //獲取當前實體類物件
        ItemVO vo = mList.get(position);
        //設定
        holder.text.setText(vo.getmName());
        holder.img.setImageResource(vo.getmImg());
    }

    //數量
    @Override
    public int getItemCount() {
        return mList.size();
    }

    //內部類
    class ViewHolder extends RecyclerView.ViewHolder{
        //行佈局中的控制元件
        ImageView img;
        TextView text;
        //檢視
        View view;
        public ViewHolder(View itemView) {
            super(itemView);
            view = itemView;
            //繫結控制元件
            img = (ImageView) itemView.findViewById(R.id.item_img);
            text = (TextView) itemView.findViewById(R.id.item_text);
        }
    }
}

先修改了ViewHolder,在ViewHolder中添加了view變數來儲存子項最外層佈局例項,然後再onCreateViewHolder()中註冊監聽就好了。
這也是RecyclerView的強大之處,可以輕鬆的對子項中的任意控制元件設定點選事件。