ag旗舰厅官网_ag旗舰厅下载客户端

热门关键词: ag旗舰厅官网,ag旗舰厅下载客户端

网络编程

当前位置:ag旗舰厅官网 > 网络编程 > 平淡地抬高,RecyclerView多职能汇聚适配器

平淡地抬高,RecyclerView多职能汇聚适配器

来源:http://www.pedaLyourcycLe.com 作者:ag旗舰厅官网 时间:2019-09-30 16:18

从读书到专业,一晃搞Android也早就有几年了,用的最多控件不外乎就那么多少个,当中列表控件用起来相对来讲相比较麻烦,越发是出了RecyclerView日后。这段时间突发奇想做一个通用的适配器那样就不用每回写重复的事物了那多爽啊!这里还要出色多谢一下英特网那一个技能博客大神们,相当多东西都以以史为鉴他们的合计。

本文为新手窝小编蒋志碧的连载。“从 0 开始支付一款直播 应用程式 ”种类来聊天时下最火的直播 应用软件,怎么样完整的兑现贰个类"Tencent直播"的商业化项目
录制地址:http://www.cniao5.com/course/10121

为什么只封装适配器呢?虽说把RecyclerView手拉手装进就能够做出越多好用的遵循,客商体验也会更加好,但或者是历史遗留阴影,从前用旁人的开源控件时总轻巧出点难题。今后那样正是二个不过的适配器,不用思量列表的布局是线性的依旧网格的等看似题材。与分界面非亲非故,只干干净净的概念了逻辑法则,这种感到太爽了~


谈到底,GitHub 上体系地址传送门:SuperAdapter

【从 0 起头开辟一款直播 APP】3.1 高层封装之 Adapter — ListView & GridView
【从 0 开头支付一款直播 应用程式】3.2 高层封装之 Adapter — RecyclerView 兑现单布局体现
【从 0 开头开荒一款直播 应用程式】3.3 高层封装之 Adapter -- RecyclerView 完毕多条目展现
【从 0 早先支付一款直播 应用程式】3.4 高层封装之 Adapter -- RecyclerView 高贵的增加Header、Footer

SuperAdapter 是对RecyclerView.Adapter进展包装并将众多常用功用集成之中的一个Android库。你不必要为各样列表单独去写ViewHolder后再声称控件,当创设没有供给选定的列表时你居然无需单独创立类去继续RecyclerView.Adapter定制适配器,只要在ActivityFragment中简易写下几行代码就能够兑现,有效的减化了复写代码的数据。


  • 登时绑定单一布局列表
  • 简化多类型布局列表
  • 列表点击事件
  • 分页展现数据
  • 自定义列表独一最上部Header
  • 自定义列表尾巴部分Footer
  • 上拉自动加载更加的多多少
  • 增添空数据提示视图

一、高贵的增加 Header、Footer

上一章解说了 RecyclerView 封装的多条目款项达成聊天分界面,接下去批注RecyclerView 完成加多 Header、Footer。运维效果如下:

您须求在类型的根 build.gradle 到场如下JitPack仓库链接:

线性布局

图片 1

allprojects { repositories { ... maven { url 'https://jitpack.io' } }}

网格布局

图片 2

RecyclerView 系统未有封装增添底部和尾巴部分方法,但是 ListView 和 GridView 有包装,通过查阅源码,可以接近封装叁个加多底部和尾巴的类。ListView 本身也不援助底部和背后部分,是在 ListView 上做了一层包裹。

ListView 源码深入分析 -- ListView.addHeaderView(View v, Object data, boolean isSelectable)

public void addHeaderView(View v, Object data, boolean isSelectable) {
        final FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
        mHeaderViewInfos.add(info);
        mAreAllItemsSelectable &= isSelectable;

        //判断 Adapter 是否为空,不判断无法添加头部
        // Wrap the adapter if it wasn't already wrapped.
        if (mAdapter != null) {
            //判断是否有被包裹过
            if (!(mAdapter instanceof HeaderViewListAdapter)) {
                wrapHeaderListAdapterInternal();
            }

            //观察者模式,头部添加通知
            // In the case of re-adding a header view, or adding one later on,
            // we need to notify the observer.
            if (mDataSetObserver != null) {
                mDataSetObserver.onChanged();
            }
        }
    }

**ListView 源码剖判 -- **HeaderViewListAdapter.java

public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {

    private final ListAdapter mAdapter;

    // These two ArrayList are assumed to NOT be null.
    // They are indeed created when declared in ListView and then shared.
    //存放头部和底部集合
    ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
    ArrayList<ListView.FixedViewInfo> mFooterViewInfos;

    public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
                                 ArrayList<ListView.FixedViewInfo> footerViewInfos,
                                 ListAdapter adapter) {
        //原始列表 Adapter
        mAdapter = adapter;
        //......
    }

   //移除头部
    public boolean removeHeader(View v) {
        for (int i = 0; i < mHeaderViewInfos.size(); i++) {
            ListView.FixedViewInfo info = mHeaderViewInfos.get(i);
            if (info.view == v) {
                mHeaderViewInfos.remove(i);

                mAreAllFixedViewsSelectable =
                        areAllListInfosSelectable(mHeaderViewInfos)
                        && areAllListInfosSelectable(mFooterViewInfos);

                return true;
            }
        }

        return false;
    }

    //移除底部
    public boolean removeFooter(View v) {
        for (int i = 0; i < mFooterViewInfos.size(); i++) {
            ListView.FixedViewInfo info = mFooterViewInfos.get(i);
            if (info.view == v) {
                mFooterViewInfos.remove(i);

                mAreAllFixedViewsSelectable =
                        areAllListInfosSelectable(mHeaderViewInfos)
                        && areAllListInfosSelectable(mFooterViewInfos);

                return true;
            }
        }

        return false;
    }

    //获取条目 
    public int getCount() {
        if (mAdapter != null) {
            //头部条目 + Adapter 条目 + 底部条目
            return getFootersCount() + getHeadersCount() + mAdapter.getCount();
        } else {
            return getFootersCount() + getHeadersCount();
        }
    }

    //getView 
    public View getView(int position, View convertView, ViewGroup parent) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        //判断当前位置是否为头部
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).view;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getView(adjPosition, convertView, parent);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        //判断当前位置是否为底部
        return mFooterViewInfos.get(adjPosition - adapterCount).view;
    }

    //getItemViewType 和 RecyclerView 相似
    public int getItemViewType(int position) {
        int numHeaders = getHeadersCount();
        if (mAdapter != null && position >= numHeaders) {
            int adjPosition = position - numHeaders;
            int adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            }
        }

        return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
    }
}

依赖 ListView 的头顶加多类,经过改写,能够拿走大家协和的封装类,底部和尾巴部分或然有七个,因而要求用集合标志,这里运用 SparseArray。

public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    //不包含头部和底部
    private RecyclerView.Adapter mAdapter;

    //由于头部和底部可能有多个,需要用标识来识别
    private int BASE_HEADER_KEY = 5500000;
    private int BASE_Footer_KEY = 6600000;

    //头部和底部集合 必须要用map集合进行标识 key->int  value->object
    SparseArray<View> mHeaderViews;
    SparseArray<View> mFooterViews;

    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
        mAdapter = adapter;
        mHeaderViews = new SparseArray<>();
        mFooterViews = new SparseArray<>();
    }

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

        //区分头部和底部,根据ViewType来
        //ViewType可能有三部分  头部 底部 Adapter

        //判断是否为头部
        if (isHeaderViewType(viewType)) {
            View headerView = mHeaderViews.get(viewType);
            //header
            return createHeaderOrFooterViewHolder(headerView);
        }

        //判断是否为底部
        if (isFooterViewType(viewType)) {
            View footerView = mFooterViews.get(viewType);
            //footer
            return createHeaderOrFooterViewHolder(footerView);
        }

        //列表
        return mAdapter.onCreateViewHolder(parent, viewType);
    }


    /**
     * 创建头部和底部ViewHolder
     * @param view
     * @return
     */
    private RecyclerView.ViewHolder createHeaderOrFooterViewHolder(View view) {
        return new RecyclerView.ViewHolder(view) {};
    }

    @Override
    public int getItemViewType(int position) {
        //position -> viewtype  头部 底部 adapter  必须要用map集合进行标识
        //if(头部)return 头部 key
        //if(中间位置)return mAdapter.getItemViewType(position);
        //if(底部) return 底部 key

        //header
        if (isHeaderPosition(position)) {
            return mHeaderViews.keyAt(position);
        }

        // footer
        if (isFooterPosition(position)) {
            position = position - mHeaderViews.size() - mAdapter.getItemCount();
            return mFooterViews.keyAt(position);
        }

        //adapter
        position = position - mHeaderViews.size();
        return mAdapter.getItemViewType(position);
    }


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

        //头部,底部不需要绑定数据
        if (isHeaderPosition(position) || isFooterPosition(position)) {
            return;
        }

        // Adapter
        position = position - mHeaderViews.size();
        mAdapter.onBindViewHolder(holder, position);
    }

    @Override
    public int getItemCount() {
        return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size();
    }

    //添加头部,底部
    public void addHeaderView(View view) {
        //没有包含头部
        int position = mHeaderViews.indexOfValue(view);
        if (position < 0) {
            //集合没有就添加,不能重复添加
            mHeaderViews.put(BASE_HEADER_KEY++, view);
        }
        notifyDataSetChanged();
    }

    public void addFooterView(View view) {
        //没有包含头部
        int position = mFooterViews.indexOfValue(view);
        if (position < 0) {
            //集合没有就添加,不能重复添加
            mFooterViews.put(BASE_Footer_KEY++, view);
        }
        notifyDataSetChanged();
    }

    //移除头部,底部
    public void removeHeaderView(View view) {
        //没有包含头部
        int index = mHeaderViews.indexOfValue(view);
        if (index < 0) return;
        //集合没有就添加,不能重复添加
        mHeaderViews.removeAt(index);
        notifyDataSetChanged();
    }

    public void removeFooterView(View view) {
        //没有包含底部
        int index = mFooterViews.indexOfValue(view);
        if (index < 0) return;
        //集合没有就添加,不能重复添加
        mFooterViews.removeAt(index);
        notifyDataSetChanged();
    }

    //是否为底部
    private boolean isFooterViewType(int viewType) {
        int footerPosition = mFooterViews.indexOfKey(viewType);
        return footerPosition >= 0;
    }

    //是否为头部
    private boolean isHeaderViewType(int viewType) {
        int headerPosition = mHeaderViews.indexOfKey(viewType);
        return headerPosition >= 0;
    }

    //是否为底部位置
    private boolean isFooterPosition(int position) {
        return position >= (mHeaderViews.size() + mAdapter.getItemCount());
    }

    //是否为头部位置
    private boolean isHeaderPosition(int position) {
        return position < mHeaderViews.size();
    }
}

着在你的必要依附的Module的build.gradle参预注重:

二、线性布局增添 Header、Footer

public class AdapterActivity extends BaseActivity {

    private MutipleAdaper mMutipleAdaper;
    private WrapRecyclerAdapter mWrapRecyclerAdapter;
    private RecyclerView mRecyclerView;

    @Override
    protected void setToolbar() {
    }

    @Override
    protected void setListener() {
    }

    @Override
    protected void initData() {
        Datas = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            if (i % 2 == 0) {
                Datas.add(new Item(R.drawable.tab_publish_normal,"我 get 新技能 " + i,0));
            }else {
                Datas.add(new Item(R.drawable.tab_publish_normal,"你 get 新技能 " + i,1));
            }
        }

        mMutipleAdaper = new MutipleAdaper(this,Datas);
        mWrapRecyclerAdapter = new WrapRecyclerAdapter(mMutipleAdaper);
        mRecyclerView.setAdapter(mWrapRecyclerAdapter);

        View headerView = LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false);
        View footView = LayoutInflater.from(this).inflate(R.layout.layout_footer,mRecyclerView,false);
        mWrapRecyclerAdapter.addHeaderView(headerView);
        mWrapRecyclerAdapter.addFooterView(footView);
    }

    @Override
    protected void initView() {
        mRecyclerView = obtainView(R.id.recyclerView);
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_adapter;
    }
}

compile 'com.github.JesseWuuu:SuperAdapter:x.y.z'

三、运维效果图

图片 3

在乎:上边重视中的 x.y.z 为版本号,如今流行的版本号为 -> 0.2.0

四、WrapRecyclerView -- 自定义 RecyclerView

能够观察地点使用尾部Adapter十分不和谐,须求将事先封装的布局增加到包裹 Adapter 中,能够将自定义贰个 RecyclerView,让其承继 RecyclerView,将 WrapRecyclerAdapter 传入,调用其格局。

public class WrapRecyclerView extends RecyclerView {

    private WrapRecyclerAdapter mWrapRecyclerAdapter;

    private RecyclerView.Adapter mAdapter;

    public WrapRecyclerView(Context context) {
        this(context, null);
    }

    public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        //防止多次设置Adapter
        if (mAdapter != null) {
            mAdapter = null;
        }

        this.mAdapter = adapter;

        if (adapter instanceof WrapRecyclerAdapter) {
            mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter;
        } else {
            mWrapRecyclerAdapter = new WrapRecyclerAdapter(adapter);
        }

        //删除的问题是列表的Adapter改变,但WrapRecyclerAdapter没有改,观察者模式
        super.setAdapter(mWrapRecyclerAdapter);

    }

    //添加头部,底部
    public void addHeaderView(View view) {
        //如果没有Adapter就不添加,也可以抛异常
        //必须先设置Adapter才能添加,仿照ListView的处理方式
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.addHeaderView(view);
        }
    }

    public void addFooterView(View view) {
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.addFooterView(view);
        }

    }


    //移除头部,底部
    public void removeHeaderView(View view) {
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.removeHeaderView(view);
        }
    }

    public void removeFooterView(View view) {
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.removeFooterView(view);
        }
    }
}

行使的时候任何不改变,只需求有些修改

若果您只是想打听如何行使它可以跳过本节。

五、WrapRecyclerView 的使用

布局文件无法选拔 RecyclerView,使用自定义的 WrapRecyclerView

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.dali.admin.fragment.AdapterActivity">

   <!--<android.support.v7.widget.RecyclerView-->
       <!--android:id="@+id/recyclerView"-->
       <!--android:layout_width="match_parent"-->
       <!--android:layout_height="wrap_content">-->

   <!--</android.support.v7.widget.RecyclerView>-->

   <com.dali.admin.fragment.recycler.WrapRecyclerView
       android:id="@+id/recyclerView"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"></com.dali.admin.fragment.recycler.WrapRecyclerView>

</LinearLayout>

在AdapterActivity 中只须求将 WrapRecyclerView 表明,直接调用 addHeaderView() 就足以增加底部,增加底部类似

    private WrapRecyclerView mRecyclerView; 
    View headerView = LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false);
    View footerView = LayoutInflater.from(this).inflate(R.layout.layout_footer,mRecyclerView,false);

    mRecyclerView.addHeaderView(headerView);
    mRecyclerView.addFooterView(footerView);

看样子这里,基本封装就完了,留意的意中人会发觉未有包装监听,移除尾部和底部相当粗略,间接助长监听就行

headerView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mRecyclerView.removeHeaderView(v);
    }
});

 footerView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mRecyclerView.removeFooterView(v);
        }
    });

图片 4

唯独难题来了,大家在 ViewHolder 加多监听,Adapter 条款不会移除。怎么点都没影响。

public class MutipleAdaper extends RecyclerViewAdapter<Item> {

    public MutipleAdaper(Context context, List<Item> datas) {
        super(context, datas, new MutipleTypeSupport<Item>() {
            @Override
            public int getLayoutId(Item item) {
                if (item.getType() == 1){
                    return R.layout.list_item;
                }else {
                    return R.layout.list_item1;
                }
            }
        });
    }

    @Override
    protected void bindData(RecyclerViewHolder holder, final Item item, int position) {

        holder.setText(R.id.tv1,item.getTv1())
                .setImageResource(R.id.img,item.getRes())
        .setOnClickListener(R.id.tv1, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext,item.getTv1(),Toast.LENGTH_SHORT).show();
                mDatas.remove(item);    //移除条目 item
                notifyDataSetChanged();
            }
        });
    }
}

由来是因为大家操作的 Adapter 不是同贰个,点击的条规 Adapter 是 Mutiple艾达per,WrapRecyclerView 里面WrapRecycler艾达pter 没有改观,因而尚未达成联机创新,这里供给利用到观看者情势。

咱俩得以在 ListView 的 HeaderViewListAdapter 源码里也看出有选用观看者形式。

public void registerDataSetObserver(DataSetObserver observer) {
    if (mAdapter != null) {
        mAdapter.registerDataSetObserver(observer);
    }
}

public void unregisterDataSetObserver(DataSetObserver observer) {
    if (mAdapter != null) {
        mAdapter.unregisterDataSetObserver(observer);
    }
}

作者们也要求为其丰裕观察者模式,使通告到各个Adapter,保障数据同步立异。否则列表的notifyDataSetChanged() 没效果

public class WrapRecyclerView extends RecyclerView {

    private WrapRecyclerAdapter mWrapRecyclerAdapter;
    private RecyclerView.Adapter mAdapter;

    //重写观察者类
    private AdapterDataObserver mDataObserver = new AdapterDataObserver() {
        @Override
        public void onChanged() {
            if (mAdapter == null) return;
            if (mWrapRecyclerAdapter != mAdapter)
                mWrapRecyclerAdapter.notifyDataSetChanged();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            if (mAdapter == null) return;
            if (mWrapRecyclerAdapter != mAdapter)
                mWrapRecyclerAdapter.notifyItemRemoved(positionStart);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            if (mAdapter == null) return;
            if (mWrapRecyclerAdapter != mAdapter)
                mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            if (mAdapter == null) return;
            if (mWrapRecyclerAdapter != mAdapter)
                mWrapRecyclerAdapter.notifyItemChanged(positionStart);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            if (mAdapter == null) return;
            if (mWrapRecyclerAdapter != mAdapter)
                mWrapRecyclerAdapter.notifyItemChanged(positionStart, payload);
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            if (mAdapter == null) return;
            if (mWrapRecyclerAdapter != mAdapter)
                mWrapRecyclerAdapter.notifyItemInserted(positionStart);
        }
    };


    public WrapRecyclerView(Context context) {
        this(context, null);
    }

    public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(Adapter adapter) {

        //防止多次设置Adapter
        if (mAdapter != null) {//注销观察者
            mAdapter.unregisterAdapterDataObserver(mDataObserver);
            mAdapter = null;
        }

        this.mAdapter = adapter;

        if (adapter instanceof WrapRecyclerAdapter) {
            mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter;
        } else {
            mWrapRecyclerAdapter = new WrapRecyclerAdapter(adapter);
        }

        //删除的问题是列表的 Adapter 改变,但 WrapRecyclerAdapter没有改,观察者模式
        super.setAdapter(mWrapRecyclerAdapter);

        //注册观察者模式
        mAdapter.registerAdapterDataObserver(mDataObserver);

    }

    //添加头部,底部
    public void addHeaderView(View view) {

        //如果没有Adapter就不添加,也可以抛异常
        //必须先设置Adapter才能添加,仿照ListView的处理方式
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.addHeaderView(view);
        }
    }

    public void addFooterView(View view) {
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.addFooterView(view);
        }
    }

    //移除头部,底部
    public void removeHeaderView(View view) {

        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.removeHeaderView(view);
        }
    }

    public void removeFooterView(View view) {
        if (mWrapRecyclerAdapter != null) {
            mWrapRecyclerAdapter.removeFooterView(view);
        }
    }
}

在高等高校时期懵懵懂懂的听先生说了第一次全国代表大会堆开源的含义,固然未来也照旧不太能驾驭个中的神气,不过最近几年一同走来看过众多大神们的开源代码,也好不轻便在里边获得许多的补益。

六、完整的代码

public class AdapterActivity extends BaseActivity {
    private MutipleAdaper mMutipleAdaper;
    private WrapRecyclerView mRecyclerView;
    private ArrayList<Item> Datas;

    @Override
    protected void setToolbar() {
    }

    @Override
    protected void setListener() {
    }

    @Override
    protected void initData() {
        Datas = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            if (i % 2 == 0) {
                Datas.add(new Item(R.drawable.tab_publish_normal,"我 get 新技能 " + i,0));
            }else {
                Datas.add(new Item(R.drawable.tab_publish_normal,"你 get 新技能 " + i,1));
            }
        }

        mMutipleAdaper = new MutipleAdaper(this,Datas);
        mRecyclerView.setAdapter(mMutipleAdaper);
        View headerView = LayoutInflater.from(this).inflate(R.layout.layout_header,mRecyclerView,false);
        View footerView = LayoutInflater.from(this).inflate(R.layout.layout_footer,mRecyclerView,false);
        mRecyclerView.addHeaderView(headerView);

        headerView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mRecyclerView.removeHeaderView(v);
            }
        });

        mRecyclerView.addFooterView(footerView);
        footerView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mRecyclerView.removeFooterView(v);
            }
        });

    }

    @Override
    protected void initView() {
        mRecyclerView = obtainView(R.id.recyclerView);
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_adapter;
    }
}

就算如此那几个工具只可以算是个小玩具品级,但本人依然想将它分享给志趣相投的相爱的人们,源码中基本部分本身都相信是真的的写全了批注,希望能有一致对那一个小工具感兴趣的敌人和自家一同来承接完善它,假若能 Star 一下门类就更加好啦哈哈哈~

重复利用点击事件并运维

图片 5

接下去自身将三番五次为这么些小工具增加新的实用功用,当然若是应用进度中有标题能够增加到 Issues 中,小编会日常看的。

七、网格布局增添 Header、Footer

能够看来基本作用已经完结,可是此间独有 LinearLayout 的布局,咱们运维GridLayout 布局,并为其增加底部和尾部。只须求改写布局管理器就好

 mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
 mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));

图片 6

可以旁观是这种作用,并不是操纵一行,为焚薮而田此难点,要在原布局增添贰个主意剖断是不是是 GridLayoutManager,假诺是,对其头顶和尾部突显做拍卖。

 public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
     /**
     * 解决GridLayoutManager添加头部和底部不占用一行的问题
     * @param recycler
     */
    public void adjustSpanSize(RecyclerView recycler) {
        if (recycler.getLayoutManager() instanceof GridLayoutManager) {
            final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();
            layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    boolean isHeaderOrFooter = isHeaderPosition(position) || isFooterPosition(position);
                    return isHeaderOrFooter ? layoutManager.getSpanCount() : 1;
                }
            });
        }
    }
}

此办法要在卷入的RecyclerView中调用

public class WrapRecyclerView extends RecyclerView {
    @Override
    public void setAdapter(Adapter adapter) {
        //解决GridLayout添加头部和底部也要占据一行
        mWrapRecyclerAdapter.adjustSpanSize(this);
    }
}

再次运转

图片 7

GitHub地址传送门:SuperAdapter

总结

对于 RecyclerView 的 Adapter 的封装。

假诺您的列表只出现在了八个搭架子中并不会再度用利用,那么使用SuperAdapter时就无需你单独创立类承继父类来定制化适配器,不过照旧需求遵守一项准绳:在ActivityFragment中声明SuperAdapter个性的还要须求注明您的列表数据源类型:

单条目的封装步骤

1、 ViewHolder 的卷入,承继RecyclerView.ViewHolder,实现其方法和构造函数
2、封装 ViewHolder 的 getView() 方法,幸免 findViewById 及类型转变,提供设置控件和监听的一层层措施
3、Adapter 的包裹,承袭 RecyclerView.Adapter 类,将包装的 ViewHolder 作为范型传入,将数据源作为范型传入。如:Base艾达pter<T> extends RecyclerView.Adapter<BaseViewHolder>。实现其构造方法和架空方法。
4、设置数据源,上下文对象,布局 ID,抽象绑定 ViewHolder 具体完结,将 ViewHolder 和数据源作为参数字传送递出去,让顾客对数据实行相应管理。

List<DataEntity> mData;SuperAdapter<DataEntity> mAdapter; 

多条目的封装

1、在单条款基础上经过构造函数字传送递三个提供布局的接口,通过 ViewType 类型判定毕竟使用什么布局。
2、在 getItemViewType() 方法中判别布局项目,在 onCreateViewHolder() 方法中推断是或不是必要多布局,依据客户供给完毕分裂的构造函数

假让你的列表会在多处重复使用,那时你须求将 SuperAdapter 封装成自定义的 Adapter,上边会有特意一节讲封装 SuperAdapter 须要注意的事项,此处先不提。

头部和底部添加

1、查看 ListView 的 addHeaderView() 及其有关源码,明白加多尾部和尾部的现实思路,依据其卷入实行编辑大家友好的艺术。
2、尾部和尾部思虑使用容器存储,且必要实行标记,选拔 android 为我们提供的 SparseArray 举行仓库储存,范型为 View 类型。
3、getItemViewType() 方法依照 position 实行剖断是底部、尾巴部分依然条目款项Adapter。
3、onCreateViewHolder() 方法是布局 ViewHolder 的,此处应该有三类 ViewHolder,底部,底部,条款 Adapter,依照 ViewType 来举办决断是什么样品种的 ViewHolder,并相应的开展结构。
4、onBindViewHolder() 方法是绑定条约数据的,尾部和后面部分是无需绑定数据的,由此须要将其免除在外,在对条目Adapter 进行绑定数据。
5、最终加多addHeaderView()、addFooterView()、removeHeaderView()、removeFooterView() 等方法,封装算差不离实现。
6、对 RecyclerView 举办重写,其实正是对 RecyclerView 进行一层包裹,将打包的可加多尾部和尾巴部分的 Adapter 注脚,并调用其艺术就行了,变成和 ListView 同样能够直接增多尾部和尾部的自定义控件。
7、要贯彻真正的点击同步,须求运用阅览者方式,完成 Adapter 操作公告一齐。
8、对于 GridView 加多底部不能把持一行进行对应管理。

对此 RecyclerView 的包装讲到此,有不足的地方招待指正。

体贴入妙菜鸟窝官方网站,无需付费领到140套开源项目

图片 8

菜鸟窝官方网址公号二维码.png

参预新手直播—实战app交流群

图片 9

微信图片_20170807101053.png

绑定单一布局列表的不二法门很轻便,只需求在SuperAdapter的构造函数中加多布局文件的layoutId与数据源就可以。

SuperAdapter<DataEntity> adapter = new SuperAdapter<DataEntity>(R.layout.view_list_item_1){ @Override public void bindView(ViewHolder itemView, DataEntity data,int position) { // 此处写绑定itemview中的控件逻辑 itemView.<TextView>getView(R.id.text_1).setText(data.getTitle; Button button = holder.<Button>getView(R.id.button); button.setEnabled(entity.IsEnabled; } };

大家需求在章程 void bindView(ViewHolder itemView, DataEntity data,int position) 中绑定列表每一种条约中的控件并举办逻辑管理。当中措施参数ViewHolder itemView 为自定义 ViewHolder

通用ViewHolder

为方便管理,SuperAdapter 中具备的 ViewHolder 均为一个通用的自定义 ViewHolder ,在那之中它对外提供了一个 <T extends View>T getView(int viewId) 方法来替代 View findViewById(int ViewId)得到布局中的控件,目标是简化绑定控件方法以及对每一种条款中的子 view 做了差不离的缓存,具体行使格局上述代码段中有反映。

绑定六连串型布局文件供给构造器MultiItemViewBuilder<T>来补助适配器分明每一个地方调用对应的布局文件。同理,评释属性同一时候须求表明数据源类型:

MultiItemViewBuilder<DataEntity> multiItemViewBuilder;

MultiItemViewBuilder内需你完结多个章程:

  • int getItemType(int position,T data),通过参数中的地方和数据源来判定重返ItemView类型,ItemView类型的值需自定义。
  • int getLayoutId,通过剖断itemType归来对应的布局文件id。
MultiItemViewBuilder<DataEntity> multiItemViewBuilder = MultiItemViewBuilder<TestEntity>() { @Override public int getLayoutId { if (type == 0){ return R.layout.view_item_normal; } return R.layout.view_item_other; } @Override public int getItemType(int position, DataEntity data) { if(entity.isTest{ return 0; }else{ return 1; } } };

最后,将MultiItemViewBuilder平昔助长到SuperAdapter构造函数中就可以:

mAdapter = new SuperAdapter<DataEntity>(multiItemViewBuilder,mData) { @Override public void convert(ViewHolder holder, DataEntity entity) { // 此处写绑定itemview中的控件逻辑 } };

终极在形式convert()中绑定控件逻辑时须要针对不相同的控件类型分别处理。

绑定点击事件:

mAdapter.setOnItemClickListener(new SuperAdapter.OnItemClickListener<DataEntity>() { @Override public void onItemClick(int position, DataEntity entity) { // 此处写点击事件的逻辑 }});

绑定长按事件:

mAdapter.setOnItemLongClickListener(new SuperAdapter.OnItemLongClickListener<DataEntity>() { @Override public void onItemLongClick(int position, DataEntity entity) { // 此处写长按事件的逻辑 }});

空数据视图是指列表的数据源数据为空时呈现的提示视图。设置的接纳办法非常轻易:

mAdapter.setEmptyDataView(R.layout.empty_view);

在为列表增多了 Header 与 Footer 后即便数据源为空也不认为要求出示空视图

为何要说是列表“独一顶端”的 Header 呢?因为除该 Header 外,还应该有一种用于呈现分类音讯的 Header ,类似与报纸发表录中通过首字母 A~Z 顺序彰显联系人。

自定义尾部控件的本来面目实际上就是列表中的三个非同一般ItemView,它永恒存在列表最上方的职责且跟随列表滑动。

增多自定义头部须求完结一个头顶构造器来治本自定义底部布局:

HeaderBuilder builder = new HeaderBuilder() { @Override public int getHeaderLayoutId() { return R.layout.view_header; } @Override public void bindHeaderView(ViewHolder holder) { ImageView background = holder.getView(R.id.header_img); holder.<TextView>getView(R.id.header_name).setText("Test UserName); }};

构造器接口中有两个回调方法:

  • int getLayoutId() 设置自定义底部的布局id;
  • void convert(ViewHolder view) 绑定布局中的控件及丰裕逻辑;

聊到底,将促成好的头顶构造器加多到适配器中就能够:

mAdapter.addHeader;

开发中。。。

本条职能有一些困难啊。。。

Footer 是为满意特殊须要平昔存在于列表底部的ItemView,平常状态下是协作列表分页加载数据应用。增加Footer 的法子与在此以前加多 Header 的办法类似,需求三个构造器管理:

FooterBuilder builder = new FooterBuilder() { /** * 获取Footer的布局文件Id */ @Override public int getFooterLayoutId() { return R.layout.view_footer; } /** * 非用于分页加载更多数据状态下Footer的界面逻辑处理 */ @Override public void onNormal(ViewHolder holder) { holder.<ProgressBar>getView(R.id.footer_progress).setVisibility(View.GONE); holder.<TextView>getView(R.id.footer_msg).setText; } /** * 分页加载更多数据 - “正在加载数据中” 状态的界面逻辑处理 */ @Override public void onLoading(ViewHolder holder) { holder.<ProgressBar>getView(R.id.footer_progress).setVisibility(View.VISIBLE); holder.<TextView>getView(R.id.footer_msg).setText("正在加载数据中"); } /** * 分页加载更多数据 - “加载数据失败” 状态的界面逻辑处理 * * @param msg 数据加载失败的原因 */ @Override public void onLoadingFailure(ViewHolder holder, String msg) { holder.<ProgressBar>getView(R.id.footer_progress).setVisibility(View.GONE); holder.<TextView>getView(R.id.footer_msg).setText; } /** * 分页加载更多数据 - “没有更多数据” 状态的界面逻辑处理 */ @Override public void onNoMoreData(ViewHolder holder) { holder.<ProgressBar>getView(R.id.footer_progress).setVisibility(View.GONE); holder.<TextView>getView(R.id.footer_msg).setText; }};

因为 Footer 须求日常同盟列表分页加载数据利用,所以在构造器中除了正规使用情状下的方法onNormal(ViewHolder holder)外还提供了多少个用于管理分页加载数据状态的诀要:

  • onLoading(ViewHolder holder) 正在加载数据中
  • onLoadingFailure(ViewHolder holder, String msg) 数据加载失败,msg为退步的源委
  • onNoMoreData(ViewHolder holder) 已经加载完全部数据

末段,将构造器加多到 SuperAdapter 中:

mAdapter.addFooter;

简易Footer构造器SimpleFooterBuilder

考虑到协会 Footer 的进度有个别麻烦, SuperAdapter 库中提供了一个简易的中间定义好的 Footer 构造器 SimpleFooterBuilder,使用办法很简短:

mAdapter.addFooter(new SimpleFooterBuilder("这是个底部","正在加载数据中","加载数据失败","已经到底啦"));

SimpleFooterBuilder构造方法中的4个参数依次对应着 Footer 的符合规律方式、正在加载、加载退步、加载完成那二种情景的提示音信。

只顾!在安装分页加载数据前显明要先增加Footer

在动用该功用时,客商能够本身设置分页央求数据的初叶页,每当列表滑动到底层的时候就能够按事先安装的页数依次拉长央求新的多少。

安装分页加载数据调用 SuperAdapter 的setPaginationData()方法就能够,然而在那前面需求三个加载数据监听器LoadDataListener来治本数据的加载状态,当列表需求加载新的多少时就能调用监听器的onLoadingData()格局,该办法有多个参数:

  • int loadPage 供给加载新数据的页数
  • LoadDataStatus loadDataStatus 分页加载数据的情景调整器

分页加载数据的动静调控器LoadDataStatus 提供了三种情景:

  • onSuccess(List<T> datas) 数据诉求成功调用该办法传入新数据
  • onFailure(String msg) 数据央浼失利调用该办法传入失利音讯
  • onNoMoreData() 数据总体加载实现调用该办法

注意!加载数据鲜明要调用状态调控器LoadDataStatus中的方法给列表加载状态做报告

现实的落到实处代码:

// 分页加载数据的起始页private static final int START_PAGE = 0;......// 实现加载数据监听器LoadDataListener listener = new LoadDataListener() { @Override public void onLoadingData(final int loadPage, final LoadDataStatus loadDataStatus) { DataManager.getListPaginationData(loadPage,new Callback(){ @Override public void onSuccess(List<String> datas){ if(datas.size{ loadDataStatus.onNoMoreData(); }else{ loadDataStatus.onSuccess; } } @Override public void onFailure(String msg){ loadDataStatus.onFailure; } @Override public void onError(){ loadDataStatus.onFailure; } }); }}// 设置分页加载数据mAdapter.setPaginationData(START_PAGE, listener);

SuperAdaper类中提供了五个有参构造方法:

  • SuperAdapter(int layoutId )
  • SuperAdapter(MultiItemViewBuilder multiItemViewBuilder)

她们落到实处了分歧种类的子布局,所以持续SuperAdapter时要Super()里面三个构造方法,不过你早晚不愿意每回实例化适配器都要定义它们,所以提出在您的自定义类少将布局项目以static艺术定义好:

private static int layoutId = R.layout.view_list_item;

或者

private static MultiItemViewBuilder<TestEntity> multiItemViewBuilder = new MultiItemViewBuilder<TestEntity>() { @Override public int getLayoutId { if (type == 0){ return R.layout.view_list_item_1; }else { return R.layout.view_list_item_2; } } @Override public int getItemType(int position, TestEntity data) { return data.getType(); } };

这么自定义类的构造方法中就不须要填写参数:

public MineAdapter() { super; // do something}

或者

public MineAdapter() { super(multiItemViewBuilder); // do something}

本文由ag旗舰厅官网发布于网络编程,转载请注明出处:平淡地抬高,RecyclerView多职能汇聚适配器

关键词:

上一篇:没有了

下一篇:调用android平台功能,进行分享