安卓BottomSheet实现——类定义

item类的定义

上一节我们定义了样式,现在我们开始进行类编写。首先我们知道整个BottomSheet是由一个个item组成的,而我们也是使用了recyclerview来显示出所有的item,所以我们先创建一个 BottomSheetItem.java

interface BottomSheetItem {
    String getTitle();
}

这里定义了一个接口,因为item的种类有很多,除了可点击传统的item以外,我们还有分隔符与标题,所以这个接口来使他们都统一的行为。只有一个函数用来返回item的title。

然后我们来实现传统的可点击的item,创建一个 BottomSheetMenuitem.java

class BottomSheetMenuItem implements BottomSheetItem {

    @ColorInt
    private int mTextColor;

    @ColorInt
    private int mTintColor;

    private Drawable mIcon;
    private String mTitle;
    private int mId;
    private MenuItem mMenuItem;

    @DrawableRes
    private int mBackground;

    public BottomSheetMenuItem(MenuItem item,@ColorInt int textColor, @DrawableRes int background,
                               @ColorInt int tintColor) {
        mMenuItem = item;
        mIcon = item.getIcon();
        mId = item.getItemId();
        mTitle = item.getTitle().toString();
        mTextColor = textColor;
        mBackground = background;
        mTintColor = tintColor;

        if (mTintColor != -1) {
            mIcon = DrawableCompat.wrap(mIcon);
            DrawableCompat.setTint(mIcon, mTintColor);
        }
    }

    public Drawable getIcon() {
        return mIcon;
    }

    public MenuItem getMenuItem() {
        return mMenuItem;
    }

    @DrawableRes
    public int getBackground() {
        return mBackground;
    }

    public int getId() {
        return mId;
    }

    @ColorInt
    public int getTextColor() {
        return mTextColor;
    }

    @Override
    public String getTitle() {
        return mTitle;
    }
}

很简单,一个图标,一个标题,一个id,和一个目录项,还有三个可能看起来比较奇怪的东西,但是看名字也明白是用来定义样式的,字体颜色,背景等等。对于整个BottomSheet,我们的处理是定义menu文件,然后在menu里读取一个个MenuItem,处理后作为我们的item。由于是在menu文件中编写,所以我们也只需要get函数,而不需要set函数了。

标题类型的item与分隔符的item非常简单,这里就不再说明。

BottomSheetHeader.java

class BottomSheetHeader implements BottomSheetItem {

    private String mTitle;

    @ColorInt
    private int mTextColor;

    public BottomSheetHeader(String title, @ColorInt int color) {
        mTitle = title;
        mTextColor = color;
    }

    @ColorInt
    public int getTextColor() {
        return mTextColor;
    }

    @Override
    public String getTitle() {
        return mTitle;
    }
}
BottomSheetDivider.java

class BottomSheetDivider implements BottomSheetItem {

    @DrawableRes
    private int mBackgroundDrawable;

    public BottomSheetDivider(@DrawableRes int background) {
        mBackgroundDrawable = background;
    }

    @DrawableRes
    public int getBackground() {
        return mBackgroundDrawable;
    }

    @Override
    public String getTitle() {
        return "";
    }
}

这样的话,我们就定义完了所有类型的item类。

item点击事件

对于传统的可点击的item,我们定义一个接口来处理它的点击操作。

BottomSheetItemClickListener.java

public interface BottomSheetItemClickListener {
    void onBottomSheetItemClick(MenuItem item);
}

这样的处理大家应该也非常熟悉。定义完了item接下来的动作就是在recyclerview里面建立item了,所以我们还需要编写一个适配器。

RecyclerView中的适配器

对于recyclerview中的适配器编写大家肯定已经非常熟悉了,这里需要注意的点无非是item类型的判断以及还需要知道BottomSheet是什么类型的。

BottomSheetItemAdapter.java

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

    public static final int TYPE_ITEM = 0;
    public static final int TYPE_HEADER = 1;
    public static final int TYPE_DIVIDER = 2;

    private List<BottomSheetItem> mItems;
    BottomSheetItemClickListener mListener;
    private int mMode;
    private int mItemWidth;

    public BottomSheetItemAdapter(List<BottomSheetItem> items, int mode,
                                  BottomSheetItemClickListener listener) {
        mMode = mode;
        mItems = items;
        mListener = listener;
    }

    public void setItemWidth(int width) {
        mItemWidth = width;
    }

    public void setListener(BottomSheetItemClickListener listener) {
        mListener = listener;
    }

    @Override
    public int getItemViewType(int position) {
        BottomSheetItem item = mItems.get(position);

        if (item instanceof BottomSheetMenuItem) {
            return TYPE_ITEM;
        } else if (item instanceof BottomSheetDivider) {
            return TYPE_DIVIDER;
        } else if (item instanceof BottomSheetHeader) {
            return TYPE_HEADER;
        }

        return super.getItemViewType(position);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mMode == BottomSheetBuilder.MODE_GRID) {
            View layout = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.bottomsheetbuilder_grid_adapter, parent, false);

            ViewGroup.LayoutParams layoutParams = layout.getLayoutParams();
            layoutParams.width = mItemWidth;
            layout.setLayoutParams(layoutParams);
            return new ItemViewHolder(layout);
        }

        if (mMode == BottomSheetBuilder.MODE_LIST) {

            if (viewType == TYPE_HEADER) {
                return new HeaderViewHolder(LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.bottomsheetbuilder_list_header, parent, false));
            }

            if (viewType == TYPE_ITEM) {
                return new ItemViewHolder(LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.bottomsheetbuilder_list_adapter, parent, false));
            }

            if (viewType == TYPE_DIVIDER) {
                return new DividerViewHolder(LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.bottomsheetbuilder_list_divider, parent, false));
            }

        }

        return new ViewHolder(LayoutInflater.from(parent.getContext())
                .inflate(R.layout.bottomsheetbuilder_list_adapter, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        BottomSheetItem item = mItems.get(position);

        if (mMode == BottomSheetBuilder.MODE_LIST) {
            if (holder.getItemViewType() == TYPE_ITEM) {
                ((ItemViewHolder) holder).setData((BottomSheetMenuItem) item);
            } else if (holder.getItemViewType() == TYPE_HEADER) {
                ((HeaderViewHolder) holder).setData((BottomSheetHeader) item);
            } else if (holder.getItemViewType() == TYPE_DIVIDER) {
                ((DividerViewHolder) holder).setData((BottomSheetDivider) item);
            }
        } else {
            ((ItemViewHolder) holder).setData((BottomSheetMenuItem) item);
        }
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        public ViewHolder(View itemView) {
            super(itemView);
        }

    }

    public class DividerViewHolder extends ViewHolder {

        public View divider;

        public DividerViewHolder(View itemView) {
            super(itemView);
            divider = itemView;
        }

        public void setData(BottomSheetDivider item) {
            int background = item.getBackground();
            if (background != 0) {
                divider.setBackgroundResource(background);
            }
        }
    }

    public class HeaderViewHolder extends ViewHolder {

        public TextView textView;

        public HeaderViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(.textView);
        }

        public void setData(BottomSheetHeader item) {
            textView.setText(item.getTitle());
            int color = item.getTextColor();

            if (color != 0) {
                textView.setTextColor(color);
            }
        }
    }


    public class ItemViewHolder extends ViewHolder implements View.OnClickListener {

        public AppCompatImageView imageView;
        public TextView textView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            imageView = (AppCompatImageView) itemView.findViewById(.imageView);
            textView = (TextView) itemView.findViewById(.textView);
        }

        public void setData(BottomSheetMenuItem item) {
            imageView.setImageDrawable(item.getIcon());
            textView.setText(item.getTitle());
            int color = item.getTextColor();
            int background = item.getBackground();

            if (color != 0) {
                textView.setTextColor(color);
            }

            if (background != 0) {
                itemView.setBackgroundResource(background);
            }

        }

        @Override
        public void onClick(View v) {
            BottomSheetMenuItem item = (BottomSheetMenuItem) mItems.get(getLayoutPosition());

            if (mListener != null) {
                mListener.onBottomSheetItemClick(item.getMenuItem());
            }
        }
    }
}

可以看到,首先我们定义三个常量来代表三种类型的item,并使用了一个mMode变量来得知BottomSheet的类型。对于item类型的判断,我们重载了 getItemViewType() 函数,来对于item 进行类型判断。并为不同的item类型构建了不同类型的ViewHolder,内部都定义了一个 setData() 函数来对于类进行赋值。对于传统的item我们还实现了 View.OnClickListener 来监听点击事件。

而在 onCreateViewHolder() 我们首先对BottomSheet的类型进行判断,这一步的主要原因是,在grid类型的BottomSheet中我们是没有标题与分隔符类型的item,所以可以少很多判断,并要加载相应的布局样式文件。在 onBindViewHolder() 的判断越是同理。

这样的话,我们就编写完了适配器。

前期的准备工作基本完成了,下面就可以开始来构建视图了。