1. 程式人生 > >使用RecyclerView實現GridView和ListView混排的效果

使用RecyclerView實現GridView和ListView混排的效果

   單位在做股票相關的app,美工切出一個圖,是一個GridView和ListView混排的效果圖,而且在滾動的時候,還要實現相關類別名有推動的效果,如下圖:

   

   錄製的效果不是很好,因為csdn只能上傳2M,所以點選的效果沒有實現。下面會下載的地址。可以下載看一下。現在說一下實現的思路。個人感覺不是很好,只是為了完成功能,如果你有更好的思路或是方法,希望能告訴我。

   1,RecyclerView雖然很靈活,可是也沒有GridView與listView混排的功能。

   2,GridLayoutManager有一個方法setSpanSizeLookup,可以設定GridView中每項的所佔的比例。

   3,類別項,GridView項,ListView項的佈局都不一樣,這個我們只能設計viewType來處理。

   4,根據設計思路類別項,GridView項,ListView項點選是會跳轉到不同的頁面的。

   好了,根據這個思路和步驟我們開始我們的程式碼吧。

   activity_main.xml,主佈局,這個沒什麼可說的,就是一個RecyclerView控制元件,外加一個用來顯示類別的佈局。

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.cg.pinnedsectionrecyclerview.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recy_pinned"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <LinearLayout
        android:id="@+id/title_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff6688">

        <TextView
            android:id="@+id/txt_Title"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:gravity="center_vertical"
            android:text="行業版塊"/>

    </LinearLayout>
</RelativeLayout>

   下面我們設定一下,三種項的佈局,類別項,GridView項,ListView項

   activity_pinned_titleitem.xml  類別項

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linear_t"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ff6688">

    <TextView
        android:id="@+id/txt_pTitle"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:gravity="center_vertical"/>

</LinearLayout>

   activity_pinned_griditem.xml  GridView項
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linear_g"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center"
    android:paddingTop="5dp"
    android:paddingBottom="5dp">
    <TextView
        android:id="@+id/txt_pGName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="股名"
        android:textSize="16dp"
        android:gravity="center"/>
    <TextView
        android:id="@+id/txt_pGValue1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="+4.12%"
        android:textSize="14dp"
        android:textColor="#ff4433"
        android:gravity="center"/>
    <TextView
        android:id="@+id/txt_pGValue2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="好名字 +4.12%"
        android:textSize="12dp"
        android:textColor="#ff4433"
        android:gravity="center"/>
</LinearLayout>

activity_pinned_listitem.xml  listView項佈局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rela_l"
    android:layout_width="match_parent"
    android:layout_height="45dp"
    android:orientation="horizontal"
    android:gravity="center_vertical">
    <TextView
        android:id="@+id/txt_pLName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="股名"
        android:textSize="16dp"
        android:layout_marginLeft="5dp"/>
    <TextView
        android:id="@+id/txt_pLValue2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+4.12%"
        android:textSize="12dp"
        android:textColor="#ff4433"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"/>
    <TextView
        android:id="@+id/txt_pLValue1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+4.12%"
        android:textSize="14dp"
        android:textColor="#ff4433"
        android:layout_marginRight="25dp"
        android:layout_toLeftOf="@+id/txt_pLValue2"/>

</RelativeLayout>

    根據上面的圖,我們做一個測試model檔案。

 myTestModel.xml

package com.example.cg.pinnedsectionrecyclerview.models;

/**
* 測試資料結構
* 作者:cg
* 時間:2016/8/18 0018 上午 11:01
*/
public class myTestModel {

    private String title;             //類別,標題
    private String name;              //股票名稱
    private String value1;            //漲跌值1
    private String value2;            //漲跌值2
    private int type;                 //資料顯示的類別 1:Grid佈局資料  2:List佈局資料 3:類別佈局資料
    private int sordid;               //分類的順序值,此值為資訊所屬類別的順序值

    public myTestModel() {
    }


    public myTestModel(String title, String name, String value1, String value2,int type,int sordid) {
        this.title = title;
        this.name = name;
        this.value1 = value1;
        this.value2 = value2;
        this.type = type;
        this.sordid = sordid;


    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue1() {
        return value1;
    }

    public void setValue1(String value1) {
        this.value1 = value1;
    }

    public String getValue2() {
        return value2;
    }

    public void setValue2(String value2) {
        this.value2 = value2;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getSordid() {
        return sordid;
    }

    public void setSordid(int sordid) {
        this.sordid = sordid;
    }
}

  好,佈局和model完成,我們來設計一下我們的adpter

 PinnedRecyAdapter.java

package com.example.cg.pinnedsectionrecyclerview.Adapter;

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.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.example.cg.pinnedsectionrecyclerview.R;
import com.example.cg.pinnedsectionrecyclerview.models.myTestModel;

import java.util.List;

/**
* RecyclerView的Adapter
* 作者:cg
* 時間:2016/8/18 0018 上午 10:47
*/
public class PinnedRecyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<myTestModel> list_data;
    private LayoutInflater inflater;
    private Context context;

    public PinnedRecyAdapter(List<myTestModel> list_data, Context context) {
        this.list_data = list_data;
        this.inflater = LayoutInflater.from(context);
        this.context = context;
    }

    /**
     * 定義點選每項的介面,此處只實現了點選,沒有實現長按
     */
    public interface OnItemClickLitener
    {
        void OnItemClick(View view, int positon, int type);
        void OnItemLongClick(View view, int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {


        View view;
        RecyclerView.ViewHolder mViewHolder;
        if(viewType==1) {

            view = inflater.inflate(R.layout.activity_pinned_griditem, parent, false);
            mViewHolder = new gViewHolder(view);
        }else if(viewType==2)
        {
            view = inflater.inflate(R.layout.activity_pinned_listitem, parent, false);
            mViewHolder = new lViewHolder(view);
        }else
        {
            view = inflater.inflate(R.layout.activity_pinned_titleitem, parent, false);
            mViewHolder = new tViewHolder(view);
        }

        return mViewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {

        switch (getItemViewType(position))
        {
            case 1:
                final gViewHolder gHolder = (gViewHolder)holder;
                gHolder.txt_pGName.setText(list_data.get(position).getName());
                gHolder.txt_pGValue1.setText(list_data.get(position).getValue1());
                gHolder.txt_pGValue2.setText(list_data.get(position).getValue2());

                if(mOnItemClickLitener!=null)
                {
                    gHolder.linear_g.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            //Toast.makeText(context,list_data.get(position).getName(),Toast.LENGTH_SHORT).show();
                            mOnItemClickLitener.OnItemClick(gHolder.itemView, position,1);
                        }
                    });
                }
                break;
            case 2:
                final lViewHolder lHolder = (lViewHolder)holder;
                lHolder.txt_pLName.setText(list_data.get(position).getName());
                lHolder.txt_pLValue1.setText(list_data.get(position).getValue1());
                lHolder.txt_pLValue2.setText(list_data.get(position).getValue2());
                if(mOnItemClickLitener!=null)
                {
                    lHolder.rela_l.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            //Toast.makeText(context,list_data.get(position).getName(),Toast.LENGTH_SHORT).show();
                            mOnItemClickLitener.OnItemClick(lHolder.itemView, position,2);
                        }
                    });
                }
                break;
            case 3:
                final tViewHolder tHolder = (tViewHolder)holder;
                tHolder.txt_pTitle.setText(list_data.get(position).getTitle());
                if(mOnItemClickLitener!=null)
                {
                    tHolder.linear_t.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            //Toast.makeText(context,list_data.get(position).getName(),Toast.LENGTH_SHORT).show();
                            mOnItemClickLitener.OnItemClick(tHolder.itemView, position,3);
                        }
                    });
                }
                break;
        }

    }

    @Override
    public int getItemViewType(int position) {

        return list_data.get(position).getType();
    }

    @Override
    public int getItemCount() {
        return list_data.size();
    }


    /**
     * 類別形式的佈局資料
     */
    class tViewHolder extends RecyclerView.ViewHolder {

        LinearLayout linear_t;
        TextView txt_pTitle;

        public tViewHolder(View itemView) {
            super(itemView);
            linear_t = (LinearLayout)itemView.findViewById(R.id.linear_t);
            txt_pTitle = (TextView)itemView.findViewById(R.id.txt_pTitle);
        }
    }

    /**
     * Grid形式的佈局資料
     */
    class gViewHolder extends RecyclerView.ViewHolder {

        LinearLayout linear_g;
        TextView txt_pGName;
        TextView txt_pGValue1;
        TextView txt_pGValue2;

        public gViewHolder(View itemView) {
            super(itemView);

            linear_g = (LinearLayout)itemView.findViewById(R.id.linear_g);
            txt_pGName = (TextView)itemView.findViewById(R.id.txt_pGName);
            txt_pGValue1 = (TextView)itemView.findViewById(R.id.txt_pGValue1);
            txt_pGValue2 = (TextView)itemView.findViewById(R.id.txt_pGValue2);
        }
    }

    /**
     * List形式的佈局資料
     */
    class lViewHolder extends RecyclerView.ViewHolder {

        RelativeLayout rela_l;
        TextView txt_pLName;
        TextView txt_pLValue1;
        TextView txt_pLValue2;

        public lViewHolder(View itemView) {
            super(itemView);

            rela_l = (RelativeLayout)itemView.findViewById(R.id.rela_l);
            txt_pLName = (TextView)itemView.findViewById(R.id.txt_pLName);
            txt_pLValue1 = (TextView)itemView.findViewById(R.id.txt_pLValue1);
            txt_pLValue2 = (TextView)itemView.findViewById(R.id.txt_pLValue2);
        }
    }

}

   這裡沒有什麼可以說的,就是根據viewtype的不同,顯示三個不同的佈局,同時定義了點選事件,這裡注意點選事件的第三個變數,type它是用來判斷我點的是哪種佈局,前臺根據這個來判斷,要跳轉的頁面。

 MainActivity.java檔案,主程式,裡面我寫了註解。

package com.example.cg.pinnedsectionrecyclerview;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.cg.pinnedsectionrecyclerview.Adapter.PinnedRecyAdapter;
import com.example.cg.pinnedsectionrecyclerview.models.myTestModel;

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

public class MainActivity extends AppCompatActivity {

    //分別定義三種顯示格式的值
    private static int GridFlag = 1;
    private static int ListFlag = 2;
    private static int titleFlag = 3;

    private Context mContext;

    private RecyclerView recy_pinned;
    private List<myTestModel> mDatas;
    private PinnedRecyAdapter pAdapter;
    private GridLayoutManager gManager;

    private LinearLayout titleLayout;
    private TextView txt_Title;
    private int lastFirstVisibleItem = -1;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mContext = MainActivity.this;

        initData();
        initControls();
    }

    /**
     * 初始化資料
     * 因為這是Grid與list的混排,所以沒法將title也就是類別,放到每條記錄裡,因為Grid型別,沒法處理。
     * 所以這裡我採用的是單獨把類別做為一個條記錄存入並且給了一個單獨的類別3
     */
    protected void initData()
    {

        mDatas = new ArrayList<>();


        myTestModel mModel1 = new myTestModel();
        mModel1.setTitle("行業版塊");
        mModel1.setName("");
        mModel1.setValue1("");
        mModel1.setValue2("");
        mModel1.setType(titleFlag);
        mModel1.setSordid(1);
        mDatas.add(mModel1);

        for(int i=0;i<6;i++)
        {

            myTestModel mModel = new myTestModel();
            mModel.setTitle("行業版塊");
            mModel.setName("行業版塊" + i);
            mModel.setValue1("+4.23%");
            mModel.setValue2("行業股" + i + " 3.24%");
            mModel.setType(GridFlag);
            mModel.setSordid(1);
            mDatas.add(mModel);
        }

        myTestModel mModel2 = new myTestModel();
        mModel2.setTitle("概念版塊");
        mModel2.setName("");
        mModel2.setValue1("");
        mModel2.setValue2("");
        mModel2.setType(titleFlag);
        mModel2.setSordid(2);
        mDatas.add(mModel2);

        for(int i=0;i<6;i++)
        {

            myTestModel mModel = new myTestModel();
            mModel.setTitle("概念版塊");
            mModel.setName("概念版塊" + i);
            mModel.setValue1("+5.23%");
            mModel.setValue2("概念股" + i + " 5.24%");
            mModel.setType(GridFlag);
            mModel.setSordid(2);
            mDatas.add(mModel);
        }

        myTestModel mModel3 = new myTestModel();
        mModel3.setTitle("瀘深A股");
        mModel3.setName("");
        mModel3.setValue1("");
        mModel3.setValue2("");
        mModel3.setType(titleFlag);
        mModel3.setSordid(3);
        mDatas.add(mModel3);

        for(int i=0;i<10;i++)
        {

            myTestModel mModel = new myTestModel();
            mModel.setTitle("瀘深A股");
            mModel.setName("瀘深A股" + i);
            mModel.setValue1("+1.23%");
            mModel.setValue2("1.24%");
            mModel.setType(ListFlag);
            mModel.setSordid(3);
            mDatas.add(mModel);
        }

        myTestModel mModel4 = new myTestModel();
        mModel4.setTitle("創業版指");
        mModel4.setName("");
        mModel4.setValue1("");
        mModel4.setValue2("");
        mModel4.setType(titleFlag);
        mModel4.setSordid(4);
        mDatas.add(mModel4);

        for(int i=0;i<15;i++)
        {

            myTestModel mModel = new myTestModel();
            mModel.setTitle("創業版指");
            mModel.setName("創業版指" + i);
            mModel.setValue1("+6.23%");
            mModel.setValue2("6.24%");
            mModel.setType(ListFlag);
            mModel.setSordid(4);
            mDatas.add(mModel);
        }

    }


    /**
     * 初始化控制元件
     */
    @TargetApi(Build.VERSION_CODES.M)
    private void initControls() {

        titleLayout = (LinearLayout)findViewById(R.id.title_layout);
        txt_Title = (TextView)findViewById(R.id.txt_Title);

        recy_pinned = (RecyclerView)findViewById(R.id.recy_pinned);

        /**
         * 在這裡,我們把LayoutManager設成Grid形式,根據實際情況,這裡我設定成三列
         * setSpanSizeLookup方法,個人感覺有點像我們xml佈局中的layout_weight,它表示Grid中的每項佔幾個位置
         * 在這裡,根據實際情況,我們可以得知,類別欄和下面的list形式資料全是每條佔滿的也就是一個佔三個的位置
         */
        gManager = new GridLayoutManager(this,3);
        gManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {

                if (position == 0 || position == 7 || position > 13) {
                    return 3;
                } else {
                    return 1;
                }
            }
        });
        recy_pinned.setLayoutManager(gManager);
        pAdapter = new PinnedRecyAdapter(mDatas,this);
        recy_pinned.setAdapter(pAdapter);

        /**
         * 這裡,我們根據控制元件的滾動情況,來對選單欄進行處理。
         * 這裡可以參看郭霖大神的http://blog.csdn.net/guolin_blog/article/details/9033553
         */
        recy_pinned.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                //取得當前螢幕可見資料的第一個值
                int firstVisibleItem = gManager.findFirstVisibleItemPosition();

                //取得當前螢幕可見資料的第一個值的類別值
                int section = mDatas.get(firstVisibleItem).getSordid();

                //取得當前螢幕可見資料的第一個值的類別值在類別順序中的下一個類別值
                int nextSecPosition = getLastIndex(section);

                if (firstVisibleItem != lastFirstVisibleItem) {
                    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) titleLayout.getLayoutParams();
                    params.topMargin = 0;
                    titleLayout.setLayoutParams(params);
                    txt_Title.setText(mDatas.get(firstVisibleItem).getTitle());
                }


                if (nextSecPosition == firstVisibleItem + 1) {
                    View childView = recyclerView.getChildAt(0);
                    if (childView != null) {

                        int titleHeight = titleLayout.getHeight();
                        int bottom = childView.getBottom();
                        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) titleLayout
                                .getLayoutParams();
                        if (bottom < titleHeight) {
                            float pushedDistance = bottom - titleHeight;
                            params.topMargin = (int) pushedDistance;
                            titleLayout.setLayoutParams(params);
                        } else {
                            if (params.topMargin != 0) {
                                params.topMargin = 0;
                                titleLayout.setLayoutParams(params);
                            }
                        }
                    }
                }
                lastFirstVisibleItem = firstVisibleItem;
            }
        });

        pAdapter.setOnItemClickLitener(new PinnedRecyAdapter.OnItemClickLitener() {

            @Override
            public void OnItemClick(View view, int positon, int type) {
                if(type==GridFlag)
                {
                    Toast.makeText(mContext, mDatas.get(positon).getName(), Toast.LENGTH_SHORT).show();
                }else if(type==titleFlag)
                {
                    Toast.makeText(mContext,mDatas.get(positon).getTitle(),Toast.LENGTH_SHORT).show();
                }else
                {
                    Toast.makeText(mContext,mDatas.get(positon).getName(),Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void OnItemLongClick(View view, int position) {

            }
        });
    }


    /**
     * 根據傳入的當前類別值,取出下一個類別的第一條記錄的排序號,就是在資料列表中的順序
     *
     * 這裡的值,大家可以根據自己的實際情況去算一下。
     *
     * @param i   當前類別值
     * @return    下一個類別的第一條記錄的排序號
     */
    private int getLastIndex(int i)
    {
        switch (i)
        {
            case 1:
                return 5;
            case 2:
                return 12;
            case 3:
                return 25;
            default:
                return 0;
        }
    }
}

   最後的結果就是上圖所顯示的結果,這裡我要說明一點,這個完全是根據設計需求做出來,感覺不是很好,而且相對來說比較死。如果你有好的方法,希望能告訴我,大家一起進步。期待你的回信。

下載地址:下載地址