裝飾設計模式——RecyclerView添加頭部和底部

裝飾設計模式也稱爲包裝設計模式,用來動態的擴展對象的功能,也是繼承關係的一種替代方案之一,也就是說在不是用繼承的方式下,採用裝飾設計模式可以擴展一個對象的功能,可以是一個對象變得越來越強大。源碼中就有很多地方用到了裝飾設計模式,IO流、ContextCompat、ListView等,ListView的添加頭部和底部就是採用裝飾設計模式來實現的,而RecyclerView沒有添加頭部和底部,其實ListView也只不過是系統給實現了而已,既然這樣可以參考ListView添加頭部和底部的方式來給RecyclerView添加頭部和底部。先寫一個普通的RecyclerView列表效果,在這效果上面進行添加;

class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.adapter_item, parent, false);
            ViewHolder holder = new ViewHolder(view);
            return holder;
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, final int position) {
            holder.tvItem.setText(list.get(position));
            holder.tvItem.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this,"點擊了"+position,Toast.LENGTH_LONG).show();
                }
            });
        }

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

        class ViewHolder extends RecyclerView.ViewHolder {
            public TextView tvItem;
            public ViewHolder(View itemView) {
                super(itemView);
                tvItem= (TextView) itemView.findViewById(R.id.tv_item);
            }
        }
    }

這個就是最常見的RecyclerView的adapter,接着定義一個adapter繼承自RecyclerView.Adapter 並通過該構造方法傳入一個adapter;

/**
 * Created by Administrator on 2019/1/12.
 * RecyclerView adapter 添加頭部和底部
 */

public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private RecyclerView.Adapter mAdapter;
    //存儲頭部
    private ArrayList<View> mHeaderView;
    //存儲底部
    private ArrayList<View> mFooterView;

    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
        this.mAdapter = adapter;
        mHeaderView = new ArrayList<>();
        mFooterView = new ArrayList<>();
        this.mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver()         {
            @Override
            public void onChanged() {
                super.onChanged();
                //更新數據
                notifyDataSetChanged();
            }
        });
    }
}

在WrapRecyclerAdapter中新增添加頭部/刪除頭部、添加底部/刪除底部的方法;

/**
     * 添加頭部
     *
     * @param view
     */
    public void addHeaderView(View view) {
        if (!mHeaderView.contains(view)) {
            mHeaderView.add(view);
            notifyDataSetChanged();
        }
    }

    /**
     * 添加底部
     *
     * @param view
     */
    public void addFooterView(View view) {
        if (!mFooterView.contains(view)) {
            mFooterView.add(view);
            notifyDataSetChanged();
        }
    }

    /**
     * 移除頭部
     *
     * @param view
     */
    public void removeHeaderView(View view) {
        if (mHeaderView.contains(view)) {
            mHeaderView.remove(view);
            notifyDataSetChanged();
        }
    }

    /**
     * 移除底部
     *
     * @param view
     */
    public void removeFooterView(View view) {
        if (mFooterView.contains(view)) {
            mFooterView.remove(view);
            notifyDataSetChanged();
        }
    }

接下來在創建ViewHolder時就要根據position的位置進行判斷,如果是頭部就牀架頭部的ViewHolder,內容就創建內容的ViewHolder,底部就創建底部的ViewHolder;

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
        int headerCount = getHeaderCount();
        if (position < headerCount) {
            //頭部
            return createHeaderViewHolder(mHeaderView.get(position));
        }
        int adjPosition = position - headerCount;
        int adapterCount = 0;
        if (mAdapter != null) {
            //內容區域
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.onCreateViewHolder(parent,mAdapter.getItemViewType(adjPosition));
            }
        }
        //底部
        return createFooterViewHolder(mFooterView.get(adjPosition - adapterCount));
    }

    /**
     * 創建頭部viewholder
     *
     * @param view
     */
    private RecyclerView.ViewHolder createHeaderViewHolder(View view) {
        return new RecyclerView.ViewHolder(view) {
        };
    }

    /**
     * 創建底部viewholder
     *
     * @param view
     * @return
     */
    private RecyclerView.ViewHolder createFooterViewHolder(View view) {
        return new RecyclerView.ViewHolder(view) {
        };
    }

在綁定參數時頭部和底部就不需要進行處理,只需要處理內容區域就可以了;

 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int numHeaders = getHeaderCount();
        if (position < numHeaders) {
            //如果是頭部直接返回
            return;
        }
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                mAdapter.onBindViewHolder(holder,adjPosition);
            }
        }
    }

使用時,在實例化頭部或底部view時,parent的傳入,要傳入當前的RecyclerView;

recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
WrapRecyclerAdapter adapter=new WrapRecyclerAdapter(recyclerAdapter);
recyclerView.setAdapter(adapter);

View headerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加頭部
adapter.addHeaderView(headerView);
View footerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加底部
adapter.addFooterView(footerView);

這樣就可以對RecyclerView進行添加頭部或者底部了,但是每次使用的時候都需要創建兩個adapter,有點麻煩,並且這樣子調用也不符合迪米特原則(最少知識原則),最好能弄成ListView那樣就最好了;那就繼續往下走吧,自定義一個RecyclerView,重寫setAdaper方法,並新增添加頭部/刪除頭部、添加底部/刪除底部的方法;

public class WrapRecyclerView extends RecyclerView {
    private WrapRecyclerAdapter 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) {
        mAdapter = new WrapRecyclerAdapter(adapter);
        super.setAdapter(mAdapter);
    }
    /**
     * 添加頭部
     *
     * @param view
     */
    public void addHeaderView(View view) {
        if (mAdapter!=null) {
            mAdapter.addHeaderView(view);
        }
    }

    /**
     * 添加底部
     *
     * @param view
     */
    public void addFooterView(View view) {
        if (mAdapter!=null) {
            mAdapter.addFooterView(view);
        }
    }

    /**
     * 移除頭部
     *
     * @param view
     */
    public void removeHeaderView(View view) {
        if (mAdapter!=null) {
            mAdapter.removeHeaderView(view);
        }
    }

    /**
     * 移除底部
     *
     * @param view
     */
    public void removeFooterView(View view) {
        if (mAdapter!=null) {
            mAdapter.removeFooterView(view);
        }
    }
}

需要注意,必須要設置了adapter纔可以添加頭部和底部;

recyclerView = (WrapRecyclerView) findViewById(R.id.id_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
//WrapRecyclerAdapter adapter=new WrapRecyclerAdapter(recyclerAdapter);
recyclerView.setAdapter(recyclerAdapter);

View headerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加頭部
recyclerView.addHeaderView(headerView);
View footerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加底部
recyclerView.addFooterView(footerView);

這樣子就和ListView的添加頭部和底部使用一樣了。

 

源碼 

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