底部导航栏

目标:
只需添加相应的按钮和相应的视图,然后就可在Activity中切换显示。
大概思路:
在底部的LinearLayout中添加相应的图标,然后设置tag,绑定相应的Fragment数组对应的下标值。点击切换的时候,根据获取到的tag值,取出数组中对应下标的Fragment,并显示出来。

新建一个BaseBottomDelegate对底部导航栏进行组装

public abstract class BaseBottomDelegate extends LatteDelegate implements View.OnClickListener{
    //将传过来的LinkedHashMap集合里面的键值对拆分之后,分别存入两个ArrayList
    private final ArrayList<BottomTabBean> TAB_BEANS=new ArrayList<>();
    private final ArrayList<BottomItemDelegate> ITEM_DELEGATES=new ArrayList<>();

    //定义一个LinkedHashMap接受传过来的页面数据
    private final LinkedHashMap<BottomTabBean,BottomItemDelegate> ITEMS=new LinkedHashMap<>();

    //当前显示fragment的页面标记
    private int mCurrentDelegate=0;
    //首次加载页面时显示的主页标记
    private int mIndexDelegate=0;
    //点击之后按钮显示的颜色
    private int mClickedColor= Color.RED;

    @BindView(R2.id.bottom_bar)
    LinearLayoutCompat mBottomBar=null;

    //让子类传入布局所需要的按钮和布局
    public abstract LinkedHashMap<BottomTabBean,BottomItemDelegate> setItems(ItemBuilder builder);

    @Override
    public Object setLayout() {
        return R.layout.delegate_bottom;
    }

    //让子类传入设置首次加载的主页
    public abstract int setIndexDelegate();

    // 让子类传入设置点击之后按钮的颜色
    @ColorInt
    public abstract int setClickedColor();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mIndexDelegate=setIndexDelegate();
        if(setClickedColor()!=0){
            mClickedColor=setClickedColor();
        }

        final ItemBuilder builder=ItemBuilder.builder();
        final LinkedHashMap<BottomTabBean,BottomItemDelegate> items=setItems(builder);
        ITEMS.putAll(items);
        //for循环取出ITEMS中的键值对的值
        for (Map.Entry<BottomTabBean,BottomItemDelegate> item : ITEMS.entrySet()){
            final BottomTabBean key =item.getKey();
            final BottomItemDelegate value =item.getValue();
            TAB_BEANS.add(key);
            ITEM_DELEGATES.add(value);
        }

    }


    @Override
    public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
        final int size=ITEMS.size();
        //for循环填充底部布局
        for (int i=0;i<size;i++){
            LayoutInflater.from(getContext()).inflate(R.layout.bottom_item_icon_text_layou,mBottomBar);
            final RelativeLayout item= (RelativeLayout) mBottomBar.getChildAt(i);
            //设置每个item的tag
            item.setTag(i);
            item.setOnClickListener(this);
            final IconTextView itemIcon= (IconTextView) item.getChildAt(0);
            final AppCompatTextView itemTitle= (AppCompatTextView) item.getChildAt(1);
            final BottomTabBean bean=TAB_BEANS.get(i);
            itemIcon.setText(bean.getIcon());
            itemTitle.setText(bean.getTitle());
            if(i == mIndexDelegate){
                itemIcon.setTextColor(mClickedColor);
                itemTitle.setTextColor(mClickedColor);
            }
        }

        //框架需要SupportFragment的数组,所以要将fragments的ArrayList转化为SupportFragment的数组
        final SupportFragment[] delegateArray=ITEM_DELEGATES.toArray(new SupportFragment[size]);
        //Fragmentation提供的设置方法
        loadMultipleRootFragment(R.id.bottom_bar_delegate_container,mIndexDelegate,delegateArray);
    }

    //重置按钮的颜色
    private void resetColor(){
        final int count = mBottomBar.getChildCount();
        for (int i=0;i<count;i++){
            final RelativeLayout item= (RelativeLayout) mBottomBar.getChildAt(i);
            final IconTextView itemIcon= (IconTextView) item.getChildAt(0);
            itemIcon.setTextColor(Color.GRAY);
            final AppCompatTextView itemTitle= (AppCompatTextView) item.getChildAt(1);
            itemTitle.setTextColor(Color.GRAY);
        }
    }

    //点击之后重新导入delegate,切换显示的内容。并设置按钮的颜色
    @Override
    public void onClick(View v) {
        final int tag= (int) v.getTag();
        resetColor();
        final RelativeLayout item= (RelativeLayout) v;
        final IconTextView itemIcon= (IconTextView) item.getChildAt(0);
        itemIcon.setTextColor(mClickedColor);
        final AppCompatTextView itemTitle= (AppCompatTextView) item.getChildAt(1);
        itemTitle.setTextColor(mClickedColor);
        //Fragmentation提供的方法
        showHideFragment(ITEM_DELEGATES.get(tag),ITEM_DELEGATES.get(mCurrentDelegate));
        //注意先后顺序
        mCurrentDelegate=tag;
    }
}

其中BottomTabBean为底部导航栏按钮对象的封装,使用的是字体图标。
字体图标是指iconify字体图标库,它是一个矢量图标库,有超过370个矢量字体图标。这些图标都是矢量字体图标,所以不仅可以无限放大而不会失真,模糊,还可以将适用于text的属性 应用于这些矢量图标上,从而实现改变图标颜色、添加阴影等效果等。具体的使用可以参考GitHub上的使用说明。

public final class BottomTabBean {
    private final CharSequence ICON;
    private final CharSequence TITLE;

    public BottomTabBean(CharSequence icon, CharSequence title) {
        this.ICON = icon;
        this.TITLE = title;
    }

    public CharSequence getIcon(){
        return ICON;
    }

    public CharSequence getTitle(){
        return TITLE;
    }
}

其中ItemBuilder的 目的是把每一个Fragment和底部按钮的对象进行绑定组装进一个LinkedHashMap的集合

public final class ItemBuilder {

    private final LinkedHashMap<BottomTabBean,BottomItemDelegate> ITEMS=new LinkedHashMap<>();

    static ItemBuilder builder(){
        return new ItemBuilder();
    }

    public final ItemBuilder addItem(BottomTabBean bean,BottomItemDelegate delegate){
        ITEMS.put(bean,delegate);
        return this;
    }

    public final ItemBuilder addItems(LinkedHashMap<BottomTabBean,BottomItemDelegate> items){
        ITEMS.putAll(items);
        return this;
    }

    public final LinkedHashMap<BottomTabBean,BottomItemDelegate> build(){
        return ITEMS;
    }

}

最后就是 底部按钮的item布局和根Fragment的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:paddingBottom="6dp"
    android:paddingTop="6dp">

    <com.joanzapata.iconify.widget.IconTextView
        android:id="@+id/icon_bottom_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentTop="true"
        android:gravity="center"
        android:textSize="25sp"/>

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/tv_bottom_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:gravity="center"/>

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--内容-->
    <android.support.v7.widget.ContentFrameLayout
        android:id="@+id/bottom_bar_delegate_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/bottom_bar"
    />

    <!-- 底部导航栏 -->
    <android.support.v7.widget.LinearLayoutCompat
        android:id="@+id/bottom_bar"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        />

</RelativeLayout>

到这里 底部导航栏封的封装就完成了,之后只要新建底部导航栏的实例,并填充数据就可以了

public class EcBottomDelegate extends BaseBottomDelegate {

    private String backgroundColor = "#ffff8800"; //底部导航栏背景色

    @Override
    public LinkedHashMap<BottomTabBean, BottomItemDelegate> setItems(ItemBuilder builder) {

        final LinkedHashMap<BottomTabBean, BottomItemDelegate> items=new LinkedHashMap<>();

        items.put(new BottomTabBean("{fa-home}","首页"),new IndexDelegate());
        items.put(new BottomTabBean("{fa-fort-awesome}","公会"),new GuildDelegate());
        items.put(new BottomTabBean("{fa-file-image-o}","图集"),new AldumDelegate());
        items.put(new BottomTabBean("{fa-user}","我的"),new PersonalDelegate());

        return builder.addItems(items).build();
    }

    @Override
    public int setIndexDelegate() {
        return 0;
    }

    @Override
    public int setClickedColor() {
        return Color.parseColor(backgroundColor);
    }

}