1. 程式人生 > >RecyclerView展示多種佈局

RecyclerView展示多種佈局

按照慣例 先看看效果圖

多種佈局效果圖

簡介

最上面是一個輪播圖,然後下面是一個橫向滑動的頻道,然後下面就是一個GridView,再下面就是正常的佈局顯示了
當然這還不算是很複雜的佈局,我這邊只是講講原理和實現步驟,更多複雜佈局可以根據這個去擴充套件

原理

給不同position的item設定不同的layout佈局, 繫結不同的ViewHolder

實現步驟

1,定義不同的viewType常量(非必須)
2,在getItemViewType方法中根據position來返回不同的viewType
3,根據getItemViewType方法返回的不同的viewType在onCreateViewHolder建立不同的ViewHolder
4,onBindViewHolder方法裡面用instanceof判斷不同的ViewHolder來做不通的賦值處理
5,注意getItemCount的返回值

開擼程式碼

1,定義不同的viewType常量

上面的圖片上可以看出,一共有4個type,輪播圖,頻道,美女,正常4個,下面是定義的常量

    private final int BANNER_VIEW_TYPE = 0;//輪播圖
    private final int CHANNEL_VIEW_TYPE = 1;//頻道
    private final int GIRL_VIEW_TYPE = 2;//美女
    private final int NORMAL_VIEW_TYPE = 3;//正常佈局

2,在getItemViewType方法中根據position來返回不同的viewType

 /**
     * 獲取item的型別
     *
     * @param position item的位置
     * @return item的型別
     * 有幾種type就回在onCreateViewHolder方法中引入幾種佈局,也就是建立幾個ViewHolder
     */
    @Override
    public int getItemViewType(int position) {
        /*
        區分item型別,返回不同的int型別的值
        在onCreateViewHolder方法中用viewType來建立不同的ViewHolder
         */
if (position == 0) {//第0個位置是輪播圖 return BANNER_VIEW_TYPE; } else if (position == 1) {//第一個是頻道佈局 return CHANNEL_VIEW_TYPE; } else if (position == 2) {//第2個位置是美女佈局 return GIRL_VIEW_TYPE; } else {//其他位置返回正常的佈局 return NORMAL_VIEW_TYPE; } }

position就是每個item的位置,根據不同的位置來返回不同的佈局type,可以根據你的需求自己穿插的來返回不同的viewType

3,根據getItemViewType方法返回的不同的viewType在onCreateViewHolder建立不同的ViewHolder
從這一步開始就是重頭戲了

以輪播圖為例子,每一個viewType都要有這幾個步驟
a,寫xml佈局:既然有輪播圖就肯定有輪播圖的佈局,我這裡用的是第三方的輪播圖,看佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="175dp"
        app:delay_time="3000"
        app:scroll_time="1500"
        app:indicator_margin="5dp"
        app:indicator_height="6dp"
        app:indicator_width="6dp"
        app:indicator_drawable_selected="@color/colorPrimary"
        app:indicator_drawable_unselected="@color/colorAccent"
         />
</LinearLayout>

沒什麼別的,就是你要展示的佈局檔案

b,建立ViewHolder內部類,繼承RecyclerView.ViewHolder,在裡面例項化你要賦值的控制元件

 /**
     * 輪播圖的ViewHolder
     */
    public static class BannerHolder extends RecyclerView.ViewHolder {
        Banner banner;

        public BannerHolder(View itemView) {
            super(itemView);
            banner = (Banner) itemView.findViewById(R.id.banner);

        }
    }

c,引入佈局,new出ViewHolder並將引入的佈局傳遞進去,在onCreateViewHolder方法裡面

if (viewType == BANNER_VIEW_TYPE) {//如果viewType是輪播圖就去建立輪播圖的viewHolder
            View view = View.inflate(context, R.layout.item_banner, null);
            BannerHolder bannerHolder = new BannerHolder(view);
            return bannerHolder;
        }

以上就是為一種佈局建立ViewHodler

下面是完整的onCreateViewHolder方法裡面判斷不同的viewType建立不同的ViewHolder的程式碼

/**
     * 建立ViewHolder,根據getItemViewType方法裡面返回的幾種型別來建立
     *
     * @param viewType 就是getItemViewType返回的type
     * @return 返回自己建立的ViewHolder
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == BANNER_VIEW_TYPE) {//如果viewType是輪播圖就去建立輪播圖的viewHolder
            view = getView(R.layout.item_banner);
            BannerHolder bannerHolder = new BannerHolder(view);
            return bannerHolder;
        } else if (viewType == CHANNEL_VIEW_TYPE) {//頻道的type
            view = getView(R.layout.item_channel);
            return new ChannelHolder(view);
        } else if (viewType == GIRL_VIEW_TYPE) {//美女
            view = getView(R.layout.item_girl);
            return new GirlHolder(view);
        } else {//正常
            view = getView(R.layout.item_normal);
            RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            view.setLayoutParams(lp);
            return new NormalHolder(view);
        }
    }

    /**
     * 用來引入佈局的方法
     */
    private View getView(int view) {
        View view1 = View.inflate(context, view, null);
        return view1;
    }

4,onBindViewHolder方法裡面用instanceof判斷不同的ViewHolder來做不通的賦值處理

直接上程式碼了,註釋很清楚了

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        //判斷不同的ViewHolder做不同的處理
        if (holder instanceof BannerHolder) {//輪播圖
            BannerHolder bannerHolder = (BannerHolder) holder;
            //呼叫設定輪播圖相關方法
            setBanner(bannerHolder);
        } else if (holder instanceof ChannelHolder) {//頻道
            ChannelHolder channelHolder = (ChannelHolder) holder;
            //設定頻道
            setChannel(channelHolder);
        } else if (holder instanceof GirlHolder) {//美女
            GirlHolder girlHolder = (GirlHolder) holder;
            GridViewAdapter adapter = new GridViewAdapter(context, girlList);
            girlHolder.gridView.setAdapter(adapter);
            girlHolder.gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(context, "美女" + position, Toast.LENGTH_SHORT).show();
                }
            });
        } else if (holder instanceof NormalHolder) {//正常佈局
            NormalHolder normalHolder = (NormalHolder) holder;
            normalHolder.textView.setText(normalList.get(position - 3));
            normalHolder.textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "點選了" + normalList.get(position - 3), Toast.LENGTH_SHORT).show();
                }
            });
        }

    }

5,注意getItemCount的返回值
稍微不注意就越界了,+3是因為除了正常的佈局還有3個不同的佈局
如果是伺服器請求資料的話就得不同的情況不同處理了

@Override
    public int getItemCount() {
        return normalList.size() + 3;
    }

下面貼出 整個RecyclerView的adapter的程式碼

package duanlian.multiplerecyclerviewdemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.youth.banner.Banner;
import com.youth.banner.BannerConfig;
import com.youth.banner.Transformer;
import com.youth.banner.loader.ImageLoader;

import java.util.List;
import java.util.Map;


/**
 * 程式猿: 段煉
 * 建立日期: 2017/4/19
 * 建立時間: 9:30
 * 本類功能:recyclerView的Adapter
 */

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context context;
    private List<String> picList;
    private List<Map<String, Object>> channelList;
    private List<Integer> girlList;
    private List<String> normalList;
    private final int BANNER_VIEW_TYPE = 0;//輪播圖
    private final int CHANNEL_VIEW_TYPE = 1;//頻道
    private final int GIRL_VIEW_TYPE = 2;//美女
    private final int NORMAL_VIEW_TYPE = 3;//正常佈局

    public RecyclerAdapter(Context context, List<String> picList, List<Map<String, Object>> channelList,
                           List<Integer> girlList, List<String> normalList) {
        this.context = context;
        this.picList = picList;
        this.channelList = channelList;
        this.girlList = girlList;
        this.normalList = normalList;
    }

    /**
     * 獲取item的型別
     *
     * @param position item的位置
     * @return item的型別
     * 有幾種type就回在onCreateViewHolder方法中引入幾種佈局,也就是建立幾個ViewHolder
     */
    @Override
    public int getItemViewType(int position) {
        /*
        區分item型別,返回不同的int型別的值
        在onCreateViewHolder方法中用viewType來建立不同的ViewHolder
         */
        if (position == 0) {//第0個位置是輪播圖
            return BANNER_VIEW_TYPE;
        } else if (position == 1) {//第一個是頻道佈局
            return CHANNEL_VIEW_TYPE;
        } else if (position == 2) {//第2個位置是美女佈局
            return GIRL_VIEW_TYPE;
        } else {//其他位置返回正常的佈局
            return NORMAL_VIEW_TYPE;
        }
    }

    /**
     * 建立ViewHolder,根據getItemViewType方法裡面返回的幾種型別來建立
     *
     * @param viewType 就是getItemViewType返回的type
     * @return 返回自己建立的ViewHolder
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if (viewType == BANNER_VIEW_TYPE) {//如果viewType是輪播圖就去建立輪播圖的viewHolder
            view = getView(R.layout.item_banner);
            BannerHolder bannerHolder = new BannerHolder(view);
            return bannerHolder;
        } else if (viewType == CHANNEL_VIEW_TYPE) {//頻道的type
            view = getView(R.layout.item_channel);
            return new ChannelHolder(view);
        } else if (viewType == GIRL_VIEW_TYPE) {//美女
            view = getView(R.layout.item_girl);
            return new GirlHolder(view);
        } else {//正常
            view = getView(R.layout.item_normal);
            RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            view.setLayoutParams(lp);
            return new NormalHolder(view);
        }
    }

    /**
     * 用來引入佈局的方法
     */
    private View getView(int view) {
        View view1 = View.inflate(context, view, null);
        return view1;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        //判斷不同的ViewHolder做不同的處理
        if (holder instanceof BannerHolder) {//輪播圖
            BannerHolder bannerHolder = (BannerHolder) holder;
            //呼叫設定輪播圖相關方法
            setBanner(bannerHolder);
        } else if (holder instanceof ChannelHolder) {//頻道
            ChannelHolder channelHolder = (ChannelHolder) holder;
            //設定頻道
            setChannel(channelHolder);
        } else if (holder instanceof GirlHolder) {//美女
            GirlHolder girlHolder = (GirlHolder) holder;
            GridViewAdapter adapter = new GridViewAdapter(context, girlList);
            girlHolder.gridView.setAdapter(adapter);
            girlHolder.gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(context, "美女" + position, Toast.LENGTH_SHORT).show();
                }
            });
        } else if (holder instanceof NormalHolder) {//正常佈局
            NormalHolder normalHolder = (NormalHolder) holder;
            normalHolder.textView.setText(normalList.get(position - 3));
            normalHolder.textView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "點選了" + normalList.get(position - 3), Toast.LENGTH_SHORT).show();
                }
            });
        }

    }

    /**
     * 設定頻道
     *
     * @param channelHolder
     */
    private void setChannel(ChannelHolder channelHolder) {
        //動態新增View
        for (int i = 0; i < channelList.size(); i++) {
            View view = View.inflate(context, R.layout.item_channel_view, null);
            ImageView ivLogo = (ImageView) view.findViewById(R.id.iv_logo);
            TextView tvChannel = (TextView) view.findViewById(R.id.tv_channel);
            Glide.with(context).load(channelList.get(i).get("pic")).into(ivLogo);
            tvChannel.setText(channelList.get(i).get("title").toString());
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            view.setLayoutParams(params);
            params.setMargins(24, 0, 24, 0);
            view.setTag(i);
            final int finalI = i;
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, channelList.get(finalI).get("title").toString(), Toast.LENGTH_SHORT).show();
                }
            });
            channelHolder.linearLayout.addView(view);
        }
    }

    /**
     * 設定輪播圖
     *
     * @param bannerHolder
     */
    private void setBanner(BannerHolder bannerHolder) {
        //設定banner樣式
        bannerHolder.banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);
        //設定圖片載入器
        bannerHolder.banner.setImageLoader(new GlideImageLoader());
        //設定圖片集合
        bannerHolder.banner.setImages(picList);
        //設定banner動畫效果
        bannerHolder.banner.setBannerAnimation(Transformer.Default);
        //設定標題集合(當banner樣式有顯示title時)
//            bannerHolder.banner.setBannerTitles(titles);
        //設定自動輪播,預設為true
        bannerHolder.banner.isAutoPlay(true);
        //設定輪播時間
//            bannerHolder.banner.setDelayTime(3500);
        //設定指示器位置(當banner模式中有指示器時)
        bannerHolder.banner.setIndicatorGravity(BannerConfig.CENTER);
        //banner設定方法全部呼叫完畢時最後呼叫
        bannerHolder.banner.start();
    }

    public class GlideImageLoader extends ImageLoader {
        @Override
        public void displayImage(Context context, Object path, ImageView imageView) {
            //Glide 載入圖片簡單用法
            Glide.with(context).load(path).into(imageView);
        }
    }

    @Override
    public int getItemCount() {
        return normalList.size() + 3;
    }

    /*****************************************下面是為不同的佈局建立不同的ViewHolder*******************************************************/
    /**
     * 輪播圖的ViewHolder
     */
    public static class BannerHolder extends RecyclerView.ViewHolder {
        Banner banner;

        public BannerHolder(View itemView) {
            super(itemView);
            banner = (Banner) itemView.findViewById(R.id.banner);

        }
    }

    /**
     * 頻道列表的ViewHolder
     */
    public static class ChannelHolder extends RecyclerView.ViewHolder {
        LinearLayout linearLayout;

        public ChannelHolder(View itemView) {
            super(itemView);
            linearLayout = (LinearLayout) itemView.findViewById(R.id.ll_channel);

        }
    }

    /**
     * 美女的ViewHolder
     */
    public static class GirlHolder extends RecyclerView.ViewHolder {
        GridView gridView;

        public GirlHolder(View itemView) {
            super(itemView);
            gridView = (GridView) itemView.findViewById(R.id.gridview);
        }
    }

    /**
     * 正常佈局的ViewHolder
     */
    public static class NormalHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public NormalHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.text);
        }
    }

}

還有些細節就不說了,請下載demo