在开发中经常遇问问到页面的滑动,这时我们需要提供一个tab页的导航条来显示滑动到了哪一页,类似这样的
但是如果我们的tab页比较少,再加上使用ActionBar,这样就会很占空间,像安卓默认提供的tab页
是不是很浪费空间,我们可以把他挪到ActionBar上,简单的方法就是使用反射
<span style="font-size:18px;">private void enableEmbeddedTabs(Object actionBar){
try {
Method setHasEmbeddedTabsMethod = actionBar.getClass().getDeclaredMethod("setHasEmbeddedTabs", boolean.class);
setHasEmbeddedTabsMethod.setAccessible(true);
setHasEmbeddedTabsMethod.invoke(actionBar, true);
} catch (Exception e) {
// TODO: handle exception
}
} </span>
结果变成这样的
这样只能显示文字,不能显示各种图片,不利于我们的拓展,也很不美观。
下面来介绍一种可以自定义在ActionBar上的tab页方法。
对于ActionBar,有一个方法是可以设置自定义的View
ActionBar.setCustomView(View view, LayoutParams layoutParams),这样再结合我们平时使用tab页的方法来定制这样的布局。类似像Fuubo
不过在GitHub上,有实现好的开源项目,https://github.com/Mirkoddd/TabBarView,我们来分析一下他的实现方法。
首先我们down下来他的源码,发现其实实现的很简单,整个库关键的就三个类
先看TabView,这个类继承自LinearLayout,是实现某个具体的Tab页,类的实现也很简单,里面只有两个空间,一个ImageView用来显示icon,一个TextView用来显示文字,在屏幕为竖的时候,是不显示文字的,因为整个ActionBar空间有限,这个实现后面再说,类里面就是一些空间的初始化以及暴漏出一些方法给外界,setText,setIcon看名字就知道是什么意思,不多解释
再看TabBarView,这个是实现整个的核心,也是继承自LinearLayout,控制整个tabs的布局,在tab导航条下面还有一条线用来显示滑动到哪个tab页,通过调用传进来的ViewPager的offset属性来确定横线的位置,然后调用ondraw方法进行绘制,贴一下代码
<span style="font-size:18px;">@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Draw the strip manually
child = getChildAt(mSelectedTab);
int height = getHeight();
if (child != null) {
float left = child.getLeft();
Log.e("child.getLeft()==========", child.getLeft()+"");
float right = child.getRight();
if (mOffset > 0f && mSelectedTab < tabCount - 1 ) {
nextChild = getChildAt(mSelectedTab + 1);
if (nextChild != null) {
final float nextTabLeft = nextChild.getLeft();
Log.e("nextChild.getLeft()==========", nextChild.getLeft()+"");
final float nextTabRight = nextChild.getRight();
left = (mOffset * nextTabLeft + (1f - mOffset) * left);
right = (mOffset * nextTabRight + (1f - mOffset) * right);
}
}
canvas.drawRect(left, height - mStripHeight, right, height, mPaint);
}
}</span>
其中的mOffset 就是实现OnPageChangeListener,实现其中的onPageScrolled方法,方法中的positionOffset是一个从0到1变化的浮点数,当滑动到下一个tab页再变回0。
当屏幕变化时tab也应该进行相应的变化,就是横排和竖排的变化,前面也提到了,当竖排时,是不显示文字的,当横排时,显示文字,像这样
其中在TabBarView中有个更新状态的方法,
<span style="font-size:18px;">public void notifyDataSetChanged() {
this.removeAllViews();
tabCount = pager.getAdapter().getCount();
for (int i = 0; i < tabCount; i++) {
if(getResources().getConfiguration().orientation==1){
//横排
addTabViewP(i, pager.getAdapter().getPageTitle(i).toString(),
((IconTabProvider) pager.getAdapter()).getPageIconResId(i));
}else{
addTabViewL(i, pager.getAdapter().getPageTitle(i).toString(),
((IconTabProvider) pager.getAdapter()).getPageIconResId(i));
}
}
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@SuppressLint("NewApi")
@Override
public void onGlobalLayout() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
mSelectedTab = pager.getCurrentItem();
}
});
}</span>
通过getResources().getConfiguration().orientation获取当前屏幕的方向,然后进行赋值。贴一下代码
<span style="font-size:18px;">/**
* 竖排
* @param i
* @param string
* @param pageIconResId
*/
private void addTabViewP(final int i, final String string, int pageIconResId) {
final TabView tab = new TabView(getContext());
tab.setIcon(pageIconResId);
tab.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
pager.setCurrentItem(i);
}
});
//长按显示文字
CheatSheet.setup(tab, string);
this.addView(tab);
}</span>
值得提醒的是,当横排时,是不需要再进行tab.setIcon(pageIconResId);避免显示两个icon。
最后CheatSheet类就一个主要的方法,setup(),就是当我们长按tab时,在下面显示文字,和actionBar默认的tab页是一样的体验,这个是用Toast来实现的,主要就是计算Toast的位置比较麻烦,其他没什么好说的。
对于这个开源项目的使用可以去GitHub上去看一下,很简单就可以搞定