Android 經過RecyclerView Adapter設置空佈局

在Android開發中,列表無數據時,通常會顯示一個空佈局。廣泛的作法是把列表佈局(如:RecyclerView)和空佈局都寫在佈局文件(xml)裏,經過對列表和空佈局的隱藏/顯示來切換須要顯示的控件。若是咱們有不少頁面都須要顯示這種空佈局,就須要每一個頁面都要寫重複的代碼。這種方法不只耦合度高,並且實現和維護麻煩。網上也有把空佈局封裝成公共組件,經過給空佈局組件設置須要替換的目標控件,把目標控件(如:RecyclerView)替換掉的作法。這兩種作法其實都是經過切換顯示不一樣的控件來實現功能的,並且都須要咱們本身去操做列表和空佈局之間的切換。那麼有沒有不須要切換控件,就可讓咱們的列表在無數據時自動顯示一個空佈局的方法呢。答案確定是有的,今天我就給你們介紹一種經過給RecyclerView設置空佈局item實現空佈局顯示的方法。java

顯示列表通常是使用RecyclerView,RecyclerView的顯示內容是由Adapter提供和管理的。Adapter知道RecyclerView是否有數據,若是沒有數據時,由Adapter提供一個空佈局給RecyclerView顯示,這樣RecyclerView的空佈局功能能就實現了。由於RecyclerView支持多種ViewType的item,因此咱們能夠把空佈局做爲一個ViewType,。當無數據時,getItemCount返回1,讓RecyclerView顯示一個item,這個item就是咱們要顯示的空佈局。item的ViewType爲TYPE_EMPTY(可隨便定義,只要不跟普通的item衝突便可),item的寬高爲match_parent,這樣空佈局就能夠鋪面RecyclerView。git

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

    // 普通的item ViewType
    private static final int TYPE_ITEM = 1;
    // 空佈局的ViewType
    private static final int TYPE_EMPTY = 2;

    private Context mContext;

    // 數據
    private List<String> mList;

    // 是否顯示空佈局,默認不顯示
    private boolean showEmptyView = false;

    public EmptyAdapter(Context context) {
        mContext = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (viewType == TYPE_EMPTY) {
            // 建立空佈局item
            return new ViewHolder(getEmptyView(parent));
        } else {
            // 建立普通的item
            View view = LayoutInflater.from(mContext).inflate(R.layout.adapter_item, parent, false);
            return new ViewHolder(view);
        }
    }

    /** * 獲取空佈局 */
    private View getEmptyView(ViewGroup parent) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.adapter_empty_view, parent, false);
        Button btnLoadData = view.findViewById(R.id.btn_load_data);
        btnLoadData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setList(initData());
            }
        });
        return view;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        // 若是是空佈局item,不須要綁定數據
        if (!isEmptyPosition(position)) {
            holder.tvItem.setText(mList.get(position));
        }
    }

    @Override
    public int getItemCount() {
        // 判斷數據是否空,若是沒有數據,而且須要顯示空佈局,就返回1。
        int count = mList != null ? mList.size() : 0;
        if (count > 0) {
            return count;
        } else if (showEmptyView) {
            // 顯示空佈局
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (isEmptyPosition(position)) {
            // 空佈局
            return TYPE_EMPTY;
        } else {
            return TYPE_ITEM;
        }
    }

    public void setList(List<String> list) {
        mList = list;
        notifyDataSetChanged();
    }

    /** * 判斷是不是空佈局 */
    public boolean isEmptyPosition(int position) {
        int count = mList != null ? mList.size() : 0;
        return position == 0 && showEmptyView && count == 0;
    }

    /** * 設置空佈局顯示。默認不顯示 */
    public void showEmptyView(boolean isShow) {
        if (isShow != showEmptyView) {
            showEmptyView = isShow;
            notifyDataSetChanged();
        }
    }

    public boolean isShowEmptyView() {
        return showEmptyView;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {

        TextView tvItem;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            tvItem = itemView.findViewById(R.id.tv_item);
        }
    }

}
複製代碼

因爲列表中的空佈局最多隻會有一個,因此它不須要在onBindViewHolder中從新綁定數據。咱們在建立空佈局的時候就能夠直接給它設置須要顯示的內容和設置點擊事件。github

在上面的例子中,我經過getEmptyView方法提供空佈局對象。這樣作是爲了讓空佈局和adapter解耦,不過在這個例子中沒有明顯的體現出來。試想,若是咱們經過一個方法或者接口提供須要的空佈局,那麼咱們就可讓具體的adapter子類(或者使用者)試下這個方法(實現接口),由子類或者外部提供具體的空佈局,讓空佈局可自定義,並且不會影響adapter的基本功能。好比咱們項目中通常都會封裝一個BaseAdapter類,或者使用第三方開源的BaseAdapter,項目中的adapter都繼承自BaseAdapter。咱們能夠把空佈局的功能集成在BaseAdapter,而且提供默認的通用空佈局。而後子類可經過重寫方法提供本身的空佈局,這樣就讓空佈局可自定義了。把空佈局功能集成到adapter後,直接使用這個adapter,在沒有數據時就會顯示空佈局了,並且無需咱們手動地調用空佈局的顯示或者隱藏。bash

mAdapter = new EmptyAdapter(this);
// 顯示空佈局
mAdapter.showEmptyView(true);
rvList.setLayoutManager(new LinearLayoutManager(this));
rvList.setAdapter(mAdapter);
複製代碼

若是是使用GridLayoutManager,爲了能讓空佈局鋪面RecyclerView,須要setSpanSizeLookup。ide

final GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
    layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            // 若是是空佈局,讓它佔滿一行
            if (mAdapter.isEmptyPosition(position)) {
                return layoutManager.getSpanCount();
            }
            return 1;
        }
    });
    rvList.setLayoutManager(layoutManager);
複製代碼

到這裏,空佈局的實現就完成了。有興趣的朋友能夠體驗一下我在GitHub提供的例子:EmptyAdapter佈局

之因此考慮把空佈局功能集成到adapter中,是由於我以前在GitHub開源了一個可分組的RecyclerView Adapter:GroupedRecyclerViewAdapter。後面收到很多反饋,但願GroupedRecyclerViewAdapter能提供空佈局的設置,因此我就想出了這種實現方式,而且給GroupedRecyclerViewAdapter集成了這個功能。今天寫這篇文章,是但願能把這種實現方法分享給你們。雖然咱們如今是給RecyclerView 的Adapter實現空佈局,可是這種思路一樣適用於ListView等列表控件。ui

相關文章
相關標籤/搜索