Recyclerview 多佈局多數據類型的處理

開場白給:醉鄉民謠

需求假定:有三個不同的數據請求源,每個數據源的佈局方式不同,利用recyclerview的方式展示在界面上

效果如下圖:
這裏寫圖片描述

這裏寫圖片描述

本次效果採用rxjava+retrofit請求數據,將所有數據合併入一個List中,在recyclerview adapter中根據類型,進行佈局的創建,並且使用了recylerview的一個setSpanSizeLookup方法,來生成不同的排列方式

先看一下Multiadpter

public class MultiTypeAdapter extends RecyclerView.Adapter<BaseViewHolder> {
    private List<Vistable> modules;
    private TypeFactory factory;
    protected Context mContext;
    public MultiTypeAdapter(List<Vistable> modules,Context context){
        mContext = context;
        this.modules = modules;
        factory = new TypeFactoryList();
    }
    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(viewType, parent, false);
        return factory.createViewHolder(viewType, view);
    }

    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        holder.bindViewData(modules.get(position),position,mContext,this);
    }

    @Override
    public int getItemCount() {
        return modules == null? 0:modules.size();
    }

    @Override
    public int getItemViewType(int position) {
        return modules.get(position).type(factory);
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager == null || !(manager instanceof GridLayoutManager)) return;
        ((GridLayoutManager) manager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                if (getItemViewType(position)== R.layout.android_layout_item){
                    return 2;
                }else if (getItemViewType(position) == R.layout.ios_layout_item){
                    return 2;
                }else
                return 1;
            }
        });
    }
}

getItemViewType使用工廠方法進行獲取,避免進行類型判斷:

首先定義了一個藉口,所有的bean類都要實現該接口,從而拿到響應的佈局,不再寫在adapter中,而是從數據源下手

public interface Vistable {
    int type(TypeFactory factory);

}

持有一個工廠類,用於根據bean獲取響應的佈局

//定義了所使用的類型,並且將viewholder的創建加入進來:抽取BaseViewHolder
public interface TypeFactory {
    int type(AndroidBean androidData);
    int type(GirlBean beautifulGirlBean);
    int type(IosBean resultBean);
    BaseViewHolder createViewHolder(int type, View itemView);
}

public abstract class BaseViewHolder extends ViewHolder{
private SparseArray sparseArray;
private View mItemView;
public BaseViewHolder(View itemView) {
super(itemView);
sparseArray = new SparseArray<>();
mItemView = itemView;
}

public <T extends View> T getView(int resId){
    View view = sparseArray.get(resId);
    if (view == null){
        view = mItemView.findViewById(resId);
        sparseArray.put(resId,view);
    }
    return (T) view;
}

public abstract void bindViewData(T data,int position,Context context,MultiTypeAdapter adapter);

}

//實現類中用於具體的實現

public class TypeFactoryList implements TypeFactory{
    public static final int ANDROID_LAYOUT = R.layout.android_layout_item;
    public static final int GIRL_LAYOUT = R.layout.girl_image_layout;
    public static final int WECHAT_LAYOUT = R.layout.ios_layout_item;
    @Override
    public int type(AndroidBean androidData) {
        return ANDROID_LAYOUT;
    }

    @Override
    public int type(GirlBean beautifulGirlBean) {
        return GIRL_LAYOUT;
    }

    @Override
    public int type(IosBean iosData) {
        return WECHAT_LAYOUT;
    }

    @Override
    public BaseViewHolder createViewHolder(int type, View itemView) {
        switch (type){
            case ANDROID_LAYOUT:
                return new AndroidViewHolder(itemView);
            case GIRL_LAYOUT:
                return new GirlViewHolder(itemView);
            case WECHAT_LAYOUT:
                return new IosViewHolder(itemView);
            default:
                return null;
        }

    }
}

這樣的好處我們再添加新類型的時候不必再去操作adapter,比較清晰,雖然代碼比較多,但閱讀起來很方便,

看一個具體的viewholer類

public class AndroidViewHolder extends BaseViewHolder<AndroidBean> {
    public AndroidViewHolder(View itemView) {
        super(itemView);
    }

    @Override
    public void bindViewData(final AndroidBean module, int position, final Context context, MultiTypeAdapter adapter) {
        LinearLayout ll = getView(R.id.multi_android_ll);
        ll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                WebActivity.loadUrl(context,module.getUrl());
            }
        });
        ((TextView) getView(R.id.multi_android_tv)).setText(module.getDesc());
        ImageView img = getView(R.id.multi_android_iv);
        GlideApp.with(context).load(R.drawable.home_six_5).into(img);

在看一個bean類

public  class AndroidBean implements Vistable{
        /**
         * _id : 5990fb20421aa96729c57239
         * createdAt : 2017-08-14T09:21:36.634Z
         * desc : PlayPauseView:讓播放、暫停按鈕優雅的過渡
         * images : ["http://img.gank.io/8ca1bb97-8d30-4deb-9645-a2c2da1970ab"]
         * publishedAt : 2017-08-14T17:04:50.266Z
         * source : web
         * type : Android
         * url : https://github.com/Lauzy/PlayPauseView
         * used : true
         * who : Lauzy
         */

        private String _id;
        private String createdAt;
        private String desc;
        private String publishedAt;
        private String source;
        private String type;
        private String url;
        private boolean used;
        private String who;
        private List<String> images;

        public String get_id() {
            return _id;
        }

        public void set_id(String _id) {
            this._id = _id;
        }

        public String getCreatedAt() {
            return createdAt;
        }

        public void setCreatedAt(String createdAt) {
            this.createdAt = createdAt;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        public String getPublishedAt() {
            return publishedAt;
        }

        public void setPublishedAt(String publishedAt) {
            this.publishedAt = publishedAt;
        }

        public String getSource() {
            return source;
        }

        public void setSource(String source) {
            this.source = source;
        }

        public String getType() {
            return type;
        }

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

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public boolean isUsed() {
            return used;
        }

        public void setUsed(boolean used) {
            this.used = used;
        }

        public String getWho() {
            return who;
        }

        public void setWho(String who) {
            this.who = who;
        }

        public List<String> getImages() {
            return images;
        }

        public void setImages(List<String> images) {
            this.images = images;
        }

    @Override
    public int type(TypeFactory factory) {
        return factory.type(this);
    }
}

使用:

public class WechatActivity extends AppCompatActivity implements CommonImpl {

    @BindView(R.id.toolbar)
    Toolbar toolbar;
    @BindView(R.id.wechat_xry)
    RecyclerView wechatXry;
    private MultiTypeAdapter adapter;
    private List<Vistable> moudles= new ArrayList<>();

    private MultiMoudle recommendMoudle;
    private GridLayoutManager manager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wechat);
        ButterKnife.bind(this);
        initoolbar();
        initView();
        initData();
        initListener();



    }

    private void initListener() {
//        adapter.setmOnItemClickListener(this);
    }

    private void initData() {
        recommendMoudle.getAllData(this);
    }

    private void initView() {
        CustomProgressDialog.show(this,"正在獲取數據...",false,null);
        recommendMoudle = new MultiMoudle();
        //設置默認的
        manager = new GridLayoutManager(this,2);
        wechatXry.setLayoutManager(manager);
        wechatXry.setNestedScrollingEnabled(false);
        wechatXry.setHasFixedSize(false);
        wechatXry.setItemAnimator(new DefaultItemAnimator());
        adapter = new MultiTypeAdapter(moudles,this);
        wechatXry.setAdapter(adapter);
    }

    private void initoolbar() {
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        toolbar.setTitle("乾貨集錦");
        toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }

    @Override
    public void loadFailed() {
        CustomProgressDialog.dismisses();
    }

    @Override
    public void addDisaposed(Disposable disposable) {

    }

    @Override
    public void loadMultiSuccess(List<Vistable> vistable) {

        moudles.addAll(vistable);
        CustomProgressDialog.dismisses();
        adapter.notifyDataSetChanged();
    }

接下說一下數據獲取的處理:因爲我們有三個數據源,我們希望等全部數據獲取完畢後,再去加載數據,那麼用Rxjava怎麼實現呢:

這就用到了zip操作符:它可以監視多個Observable,等所有的Observable上游事件處理完畢,再將其按順序進行合併,這正是我們想要的效果

來看實際運用:相信大家一看就明白了

public void getAllData(final CommonImpl listener){
        ApiService service = ServiceManager.getInstance(Constants.API_GANKIO).creat(ApiService.class);
        Observable<AndroidData> androidDataObservable = service
                .getAndroid()
                .subscribeOn(Schedulers.io());

        Observable<BeautifulGirlBean> beautifulGirlBeanObservable = service
                .getGirls()
                .subscribeOn(Schedulers.io());
        Observable<IosData> iosDataObservable = service

                .getIos()
                .subscribeOn(Schedulers.io());
//        Observable<WeChatListBean> weChatListBeanObservable = ServiceManager.getInstance(Constants.API_MOB).creat(ApiService.class)
//                .weChatSearchListBeanList(cid, page, 20)
//                .subscribeOn(Schedulers.io());

        Observable.zip(androidDataObservable, beautifulGirlBeanObservable, iosDataObservable, new Function3<AndroidData, BeautifulGirlBean, IosData, List<Vistable>>() {
            @Override
            public List<Vistable> apply(@NonNull AndroidData androidData, @NonNull BeautifulGirlBean beautifulGirlBean, @NonNull IosData iosData) throws Exception {
                List<Vistable> list = new ArrayList<Vistable>();
                list.addAll(androidData.getResults());
                list.addAll(beautifulGirlBean.getResults());
                list.addAll(iosData.getResults());
                return list;
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<List<Vistable>>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {

            }

            @Override
            public void onNext(@NonNull List<Vistable> vistables) {
                    listener.loadMultiSuccess(vistables);
            }

            @Override
            public void onError(@NonNull Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章