天天看點

RecyclerView 實作gallery畫廊效果

首先主activity的布局檔案:

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"  

    xmlns:tools="http://schemas.android.com/tools"  

    android:layout_width="match_parent"  

    android:layout_height="match_parent" >  

    <android.support.v7.widget.recyclerview  

        android:id="@+id/id_recyclerview_horizontal"  

        android:layout_width="match_parent"  

        android:layout_height="120dp"  

        android:layout_centervertical="true"  

        android:background="#ff0000"  

        android:scrollbars="none" />  

</relativelayout>  

item的布局檔案:

<?xml version="1.0" encoding="utf-8"?>  

    android:layout_width="120dp"  

    android:layout_height="120dp"  

    android:background="@drawable/item_bg02" >  

    <imageview  

        android:id="@+id/id_index_gallery_item_image"  

        android:layout_width="80dp"  

        android:layout_height="80dp"  

        android:layout_alignparenttop="true"  

        android:layout_centerhorizontal="true"  

        android:layout_margin="5dp"  

        android:scaletype="centercrop" />  

    <textview  

        android:id="@+id/id_index_gallery_item_text"  

        android:layout_width="wrap_content"  

        android:layout_height="wrap_content"  

        android:layout_below="@id/id_index_gallery_item_image"  

        android:layout_marginbottom="5dp"  

        android:layout_margintop="5dp"  

        android:textcolor="#ff0000"  

        android:text="some info"  

        android:textsize="12dp" />  

資料擴充卡:

package com.example.zhy_horizontalscrollview03;  

import java.util.list;  

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.imageview;  

import android.widget.textview;  

public class galleryadapter extends  

        recyclerview.adapter<galleryadapter.viewholder>  

{  

    private layoutinflater minflater;  

    private list<integer> mdatas;  

    public galleryadapter(context context, list<integer> datats)  

    {  

        minflater = layoutinflater.from(context);  

        mdatas = datats;  

    }  

    public static class viewholder extends recyclerview.viewholder  

        public viewholder(view arg0)  

        {  

            super(arg0);  

        }  

        imageview mimg;  

        textview mtxt;  

    @override  

    public int getitemcount()  

        return mdatas.size();  

    /** 

     * 建立viewholder 

     */  

    public viewholder oncreateviewholder(viewgroup viewgroup, int i)  

        view view = minflater.inflate(r.layout.activity_index_gallery_item,  

                viewgroup, false);  

        viewholder viewholder = new viewholder(view);  

        viewholder.mimg = (imageview) view  

                .findviewbyid(r.id.id_index_gallery_item_image);  

        return viewholder;  

     * 設定值 

    public void onbindviewholder(final viewholder viewholder, final int i)  

        viewholder.mimg.setimageresource(mdatas.get(i));  

}  

可以看到資料擴充卡與baseadapter比較發生了相當大的變化,主要有3個方法:

getitemcount 這個不用說,擷取總的條目數

oncreateviewholder 建立viewholder

onbindviewholder 将資料綁定至viewholder

可見,recyclerview對viewholder也進行了一定的封裝,但是如果你仔細觀察,你會發出一個疑問,listview裡面有個getview傳回view為item的布局,那麼這個item的樣子在哪控制?

其實是這樣的,我們建立的viewholder必須繼承recyclerview.viewholder,這個recyclerview.viewholder的構造時必須傳入一個view,這個view相當于我們listview getview中的convertview (即:我們需要inflate的item布局需要傳入)。

還有一點,listview中convertview是複用的,在recyclerview中,是把viewholder作為緩存的機關了,然後convertview作為viewholder的成員變量保持在viewholder中,也就是說,假設沒有螢幕顯示10個條目,則會建立10個viewholder緩存起來,每次複用的是viewholder,是以他把getview這個方法變為了oncreateviewholder。有興趣的自己列印下log,測試下。

最後在activity中使用:

import java.util.arraylist;  

import java.util.arrays;  

import android.app.activity;  

import android.os.bundle;  

import android.support.v7.widget.linearlayoutmanager;  

import android.view.window;  

public class mainactivity extends activity  

    private recyclerview mrecyclerview;  

    private galleryadapter madapter;  

    protected void oncreate(bundle savedinstancestate)  

        super.oncreate(savedinstancestate);  

        requestwindowfeature(window.feature_no_title);  

        setcontentview(r.layout.activity_main);  

        initdatas();  

        //得到控件  

        mrecyclerview = (recyclerview) findviewbyid(r.id.id_recyclerview_horizontal);  

        //設定布局管理器  

        linearlayoutmanager linearlayoutmanager = new linearlayoutmanager(this);  

        linearlayoutmanager.setorientation(linearlayoutmanager.horizontal);  

        mrecyclerview.setlayoutmanager(linearlayoutmanager);  

        //設定擴充卡  

        madapter = new galleryadapter(this, mdatas);  

        mrecyclerview.setadapter(madapter);  

    private void initdatas()  

        mdatas = new arraylist<integer>(arrays.aslist(r.drawable.a,  

                r.drawable.b, r.drawable.c, r.drawable.d, r.drawable.e,  

                r.drawable.f, r.drawable.g, r.drawable.h, r.drawable.l));  

使用起來也很友善,唯一的差別就是要設定layoutmanager,目前隻有一個實作類,就是linearlayoutmanager,可以設定為水準或者垂直。

最後效果圖:

RecyclerView 實作gallery畫廊效果

效果很不錯,這就是recyclerview的基本用法了,但是你會發現一個坑爹的地方,竟然沒有提供setonitemclicklistener這個回調,要不要這麼坑爹。。。

雖然它沒有提供,但是添加個onitemclicklistener對我們來說還不是小菜一碟~

我決定在adapter中添加這個回調接口:

import android.view.view.onclicklistener;  

     * itemclick的回調接口 

     * @author zhy 

     * 

    public interface onitemclicklitener  

        void onitemclick(view view, int position);  

    private onitemclicklitener monitemclicklitener;  

    public void setonitemclicklitener(onitemclicklitener monitemclicklitener)  

        this.monitemclicklitener = monitemclicklitener;  

        //如果設定了回調,則設定點選事件  

        if (monitemclicklitener != null)  

            viewholder.itemview.setonclicklistener(new onclicklistener()  

            {  

                @override  

                public void onclick(view v)  

                {  

                    monitemclicklitener.onitemclick(viewholder.itemview, i);  

                }  

            });  

很簡單,建立一個接口,提供一個設定入口,然後在onbindviewholder中判斷即可。

最後在主activity中設定監聽:

madapter = new galleryadapter(this, mdatas);  

madapter.setonitemclicklitener(new onitemclicklitener()  

    public void onitemclick(view view, int position)  

        toast.maketext(mainactivity.this, position+"", toast.length_short)  

                .show();  

});  

mrecyclerview.setadapter(madapter);  

好了,這樣就行了,看效果圖:

RecyclerView 實作gallery畫廊效果

效果還是不錯的,接下來我想改成相冊效果,即上面顯示一張大圖,下面的recyclerview做為圖檔切換的訓示器。

首先修改下布局:

布局檔案:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"  

    android:layout_height="match_parent"  

    android:orientation="vertical" >  

    <framelayout  

        android:layout_width="fill_parent"  

        android:layout_height="0dp"  

        android:layout_weight="1" >  

        <imageview  

            android:id="@+id/id_content"  

            android:layout_width="fill_parent"  

            android:layout_height="fill_parent"  

            android:layout_gravity="center"  

            android:layout_margin="10dp"  

            android:scaletype="centercrop"  

            android:src="@drawable/ic_launcher" />  

    </framelayout>  

    <com.example.zhy_horizontalscrollview03.myrecyclerview  

        android:layout_gravity="bottom"  

</linearlayout>  

添加一個顯示大圖的區域,把recyclerview改為自己定義的。

然後看我們自定義recyclerview的代碼:

import android.util.attributeset;  

import android.view.motionevent;  

public class copyofmyrecyclerview extends recyclerview  

    public copyofmyrecyclerview(context context, attributeset attrs)  

        super(context, attrs);  

    private view mcurrentview;  

     * 滾動時回調的接口 

    private onitemscrollchangelistener mitemscrollchangelistener;  

    public void setonitemscrollchangelistener(  

            onitemscrollchangelistener mitemscrollchangelistener)  

        this.mitemscrollchangelistener = mitemscrollchangelistener;  

    public interface onitemscrollchangelistener  

        void onchange(view view, int position);  

    protected void onlayout(boolean changed, int l, int t, int r, int b)  

        super.onlayout(changed, l, t, r, b);  

        mcurrentview = getchildat(0);  

        if (mitemscrollchangelistener != null)  

            mitemscrollchangelistener.onchange(mcurrentview,  

                    getchildposition(mcurrentview));  

    public boolean ontouchevent(motionevent e)  

        if (e.getaction() == motionevent.action_move)  

            mcurrentview = getchildat(0);  

            // log.e("tag", getchildposition(getchildat(0)) + "");  

            if (mitemscrollchangelistener != null)  

                mitemscrollchangelistener.onchange(mcurrentview,  

                        getchildposition(mcurrentview));  

            }  

        return super.ontouchevent(e);  

定義了一個滾動時回調的接口,然後在ontouchevent中,監聽action_move,使用者手指滑動時,不斷把目前第一個view回調回去~

關于我咋知道getchildat(0)和getchildposition()可用,起初我以為有getfirstvisibleitem這個方法,後來發現麼有;但是發現了getrecycledviewpool()看名字我覺得是viewholder那個緩存隊列,我想那麼直接取這個隊列的第一個不就是我要的view麼,後來沒有成功。我就觀察它内部的view,最後發現,第一個顯示的始終是它第一個child,至于getchildposition這個看方法就看出來了。

現在的效果:

RecyclerView 實作gallery畫廊效果

和我之前那個例子的效果是一模一樣的,不過,我還想做一些改變,我覺得gallery或者說相冊的訓示器,下面可能1000來張圖檔,我不僅喜歡手指在螢幕上滑動時,圖檔會自動切換。我還希望,如果我給訓示器一個加速度,即使手指離開,下面還在滑動,上面也會關聯 。而且我還想做些優化,直接在action_move中回調,觸發的頻率太高了,理論上一張圖檔隻會觸發一次~~

既然希望手指離開還能關聯,那麼不僅需要action_move需要監聽,還得監聽一個加速度,速度到達一定值,然後繼續移動~~再理一理,需要這麼麻煩麼,不是能滾動麼,那麼應該有onscrolllistener啊,小看一把,果然有,哈哈哈~天助我也,下面看修改後的代碼:

import android.support.v7.widget.recyclerview.onscrolllistener;  

public class myrecyclerview extends recyclerview implements onscrolllistener  

     * 記錄目前第一個view 

    public myrecyclerview(context context, attributeset attrs)  

        // todo auto-generated constructor stub  

        this.setonscrolllistener(this);  

    public void onscrollstatechanged(int arg0)  

     *  

     * 滾動時,判斷目前第一個view是否發生變化,發生才回調 

    public void onscrolled(int arg0, int arg1)  

        view newview = getchildat(0);  

            if (newview != null && newview != mcurrentview)  

                mcurrentview = newview ;  

我放棄了重寫ontouchevent方法,而是讓這個類實作recyclerview.onscrolllistener接口,然後設定監聽,在onscrolled裡面進行判斷。

至于優化:我使用了一個成員變化存儲目前第一個view,隻有第一個view發生變化時才回調~~太完美了~

看mainactivity:

import android.widget.toast;  

import com.example.zhy_horizontalscrollview03.galleryadapter.onitemclicklitener;  

import com.example.zhy_horizontalscrollview03.myrecyclerview.onitemscrollchangelistener;  

    private myrecyclerview mrecyclerview;  

    private imageview mimg ;   

        mimg = (imageview) findviewbyid(r.id.id_content);  

        mrecyclerview = (myrecyclerview) findviewbyid(r.id.id_recyclerview_horizontal);  

        mrecyclerview.setonitemscrollchangelistener(new onitemscrollchangelistener()  

            @override  

            public void onchange(view view, int position)  

                mimg.setimageresource(mdatas.get(position));  

            };  

        });  

        madapter.setonitemclicklitener(new onitemclicklitener()  

            public void onitemclick(view view, int position)  

//              toast.maketext(getapplicationcontext(), position + "", toast.length_short)  

//                      .show();  

代碼沒什麼變化~多了個設定回調~

效果圖:

RecyclerView 實作gallery畫廊效果

可以看到不僅支援手機在上面移動時的變化,如果我給了一個加速度,下面持續滾動,上面也會持續變化~~大贊~每張圖檔回調一次,效率也相當不錯。

好了,看完這邊部落格,相信大家對于recyclerview有了一定的認識,甚至對于如何改造一個控件也多了一份了解~~

如果覺得不錯,就留個言或者點個贊,表示對我的支援 

<a target="_blank" href="http://download.csdn.net/detail/lmj623565791/7684029">源碼點選下載下傳</a>

<a target="_blank" href="http://download.csdn.net/detail/lmj623565791/7684029"></a>

繼續閱讀