Android TabContainerView 实现底部导航栏
我们先来看看效果图
xiaoguo.gif
从效果图中可以看出V2.0和V1.0的区别
V2.0的Tab UI是可以实现高度定制的,上面的效果图中Tab UI共有三种样式。
V1.0的Tab UI是定死的
实现
项目的整体架构基本没变,不了解项目架构的可以先看看V1.0的文章(http://www.jianshu.com/p/7cccb5c054da#)
V2.0相对于V1.0来说就是删除了Tab类,新增了一个抽象类AbsTab,同时修改了BaseAdapter类的逻辑,下面我们先来看看AbsTab类
public abstract class AbsTab {
protected Context mContext;
/**
* Tab在TabHost中的位置,属于第mIndex个
*/
private int mIndex;
/**
* Tab类的资源View布局
*/
private View mRootView;
/**
* 当前Tab是否选中
*/
protected boolean mIsSelected;
/**
* Tab选中监听
*/
private OnTabSelectedListener onTabSelectedListener;
public AbsTab(Context context, int index) {
mContext = context;
mIndex = index;
}
/**
* 初始化View资源,得到RootView,并添加响应事件
* @param tab
* @param layoutResId
* @return
*/
protected void inflaterView(final AbsTab tab, @LayoutRes int layoutResId) {
mRootView = LayoutInflater.from(mContext).inflate(layoutResId, null);
LinearLayout.LayoutParams rootViewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
rootViewLp.weight = 1;
mRootView.setLayoutParams(rootViewLp);
initView(mRootView);
mRootView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onTabSelectedListener != null) {
onTabSelectedListener.onTabSelected(tab);
}
}
});
}
/**
* 设置选中监听
* @param onTabSelectedListener
*/
public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {
this.onTabSelectedListener = onTabSelectedListener;
}
/**
* 得到Tab 的RootView
* @return View
*/
public View getTabRootView() {
return mRootView;
}
/**
* 得到Tab Index
* @return int
*/
public int getTabIndex() {
return mIndex;
}
/**
* 显示消息提示
* @param show 是否显示
* @param count 显示数量
*/
public void showMessageTip(boolean show, int count) {};
/**
* 是否选中该Tab
* @param isSelected
*/
protected abstract void tabSelected(boolean isSelected);
/**
* 初始化RootView里的布局
* @param rootView
*/
protected abstract void initView(View rootView);
}
AbsTab类中的属性和方法上都有明确的注释,无需过多的解释,下面再来看看BaseAdapter类做了什么修改
public abstract class BaseAdapter {
private Fragment[] mFragmentArray;
private FragmentManager mFragmentManager;
protected Context mContext;
public BaseAdapter(Context context, Fragment[] fragments, FragmentManager fragmentManager) {
mContext = context;
mFragmentArray = fragments;
mFragmentManager = fragmentManager;
}
/**
* tab数量
*/
public int getCount() {
return mFragmentArray != null ? mFragmentArray.length : 0;
}
/**
* fragment 数组
*/
public Fragment[] getFragmentArray() {
return mFragmentArray;
}
public FragmentManager getFragmentManager() {
return mFragmentManager;
}
/**
* 得到tab
* @return
*/
public abstract AbsTab getTab(int index);
BaseAdapter类删除了getTextArray,getIconImageArray,getSelectedIconImageArray三个方法,新增加了getTab抽象方法。
使用
首先创建一个继承自AbsTab类的Tab类(项目中我默认实现了一个DefaultTab),然后创建一个继承自BaseAdapter类的适配器类(项目中我默认实现了一个DefaultAdapter)
TabContainerView tabContainerView = (TabContainerView) findViewById(R.id.tab_containerview_main);
tabContainerView.setAdapter(new DefaultAdapter(this, fragments, getSupportFragmentManager(), getResources().getStringArray(R.array.titleArray),
getResources().getColor(R.color.colorPrimary), iconImageArray, selectedIconImageArray));
在使用上和V1.0是一致的,最大的不同的是适配器,我们来看看DefaultAdapter适配器
public class DefaultAdapter extends BaseAdapter {
private String[] mTextArray;
private int mTextColor = Color.BLACK, mSelectedTextColor;
private int[] mIconImageArray;
private int[] mSelectedIconImageArray;
public DefaultAdapter(Context context, Fragment[] fragmentArray, FragmentManager fragmentManager, String[] textArray, int selectTextColor,
int[] iconImageArray, int[] selectedIconImageArray) {
super(context, fragmentArray, fragmentManager);
mTextArray = textArray;
mSelectedTextColor = selectTextColor;
mIconImageArray = iconImageArray;
mSelectedIconImageArray = selectedIconImageArray;
}
@Override
public AbsTab getTab(int index) {
DefaultTab defaultTab = new DefaultTab(mContext, index);
defaultTab.setText(mTextArray[index]);
defaultTab.setTextColor(mTextColor, mSelectedTextColor);
defaultTab.setIconImage(mIconImageArray[index], mSelectedIconImageArray[index]);
return defaultTab;
}
}
重点来看看getTab方法,方法中创建了一个DefaultTab类,DefaultTab是什么呢?我们进来看看他的具体实现
public class DefaultTab extends AbsTab {
/**
* tab布局信息
*/
private ImageView mIvIcon;
private TextView mTvText;
private MessageCircle mMessageCircleTip;
/**
* tab 文本颜色和图片切换资源
*/
private int mTextColor;
private int mSelectedTextColor;
private int mIconImage;
private int mSelectedIconImage;
public DefaultTab(Context context, int index) {
super(context, index);
inflaterView(this, R.layout.tab_default);
}
@Override
public void tabSelected(boolean isSelected) {
if (this.mIsSelected == isSelected) return;
mIvIcon.setImageResource(isSelected ? mSelectedIconImage : mIconImage);
mTvText.setTextColor(isSelected ? mSelectedTextColor : mTextColor);
this.mIsSelected = isSelected;
}
@Override
public void showMessageTip(boolean show, int count) {
mMessageCircleTip.setVisibility(show ? View.VISIBLE : View.GONE);
if (count == -1) {
mMessageCircleTip.setText("");
} else {
mMessageCircleTip.setText(count >= 1000 ? "999+" : count + "");
}
}
@Override
protected void initView(View rootView) {
mIvIcon = (ImageView) rootView.findViewById(R.id.iv_icon);
mTvText = (TextView) rootView.findViewById(R.id.tv_title);
mMessageCircleTip = (MessageCircle) rootView.findViewById(R.id.mc_circle);
}
public void setTextColor(int textColor, int selectedTextColor) {
mTextColor = textColor;
mSelectedTextColor = selectedTextColor;
mTvText.setTextColor(mTextColor);
}
public void setText(String text) {
mTvText.setText(text);
}
public void setIconImage(int iconImage, int selectedIconImage) {
mSelectedIconImage = selectedIconImage;
mIconImage = iconImage;
mIvIcon.setImageResource(iconImage);
}
}
它继承了AbsTab类,重写AbsTab中的抽象方法,getTab方法就是返回一个AbsTab的子类,这个子类需要开发者去创建
还有setAdapter方法逻辑也做了修改,修改最大的地方就是TabHost中的addTabs方法,V1.0版本中添加Tab是创建一个Tab类,而现在是通过适配器的getTab方法获得AbsTab类,然后添加AbsTab到TabHost当中。
总结
到此V2.0中修改的类和业务逻辑就都讲完了;开发中如果需要定制Tab UI, 首先新建一个继承自AbsTab的Tab类(项目中我默认实现了一个DefaultTab), 在新建的Tab类中创建UI布局, 给布局添加数据, 设置布局选中和不选中的UI样式, 然后新建一个继承自BaseAdapter 的适配器类, 重写getTab方法返回一个AbsTab类,就是刚创建的继承自AbsTab的Tab类,然后调用setAdapter的方法即可。
完整代码:https://github.com/chenpengfei88/TabContainerView/tree/v2.0
欢迎大家Star,Follow,谢谢。