标签栏是一个非常常见的控件,似乎也是一个比较简单的控件,但如果在标签下方加个下划线的话,就还是可以玩出挺多花来的。
网易严选的标签栏就做的很不错,里面隐藏着诸多细节:
-
<李>手动滑动页面,下划线会跟着滑动。李>
<李>选择一个标签后,下划线会有滑动过去的动画。李>
<李>选择最左端或最右端的标签,标签栏会进行滑动,使得标签向中间靠拢(如果可以滑的话)。李>
仔细分析下,需要在简单标签栏的基础上实现以下逻辑:
-
<李>画出下划线。李>
<李>监听手动滑动页面事件,实时更新下划线位置。李>
<李>切换标签时,开始下划线滑动的动画,并判断是否要同时滑动标签栏。李>
我做了一个样例程序,其中的较难点在于计算下划线的位置,和下划线的动画效果。
//根据当前选定的选项卡,得到指示器应该移动到的位置 私人Pair<浮动,Float>getIndicatorTargetLeftRight (int位置,浮动positionOffset) { 视图选项卡=tabsContainer.getChildAt(位置); Float> Pair<浮动;指标=getIndicatorLeftRight(选项卡); 浮动targetLeft=indicator.first; 浮动targetRight=indicator.second;//如果positionOffset不为0,指标正处于两个选项卡之间,需进行加权计算得到它的位置 如果(positionOffset比;0 f,,位置& lt;tabCount - 1) { 视图nextTab=tabsContainer。getChildAt(位置+ 1); Float> Pair<浮动;indicatorForNextTab=getIndicatorLeftRight (nextTab); 左浮动=indicatorForNextTab.first; 浮动对=indicatorForNextTab.second; targetLeft=(positionOffset *左+ (1 f - positionOffset) * targetLeft); targetRight=(positionOffset *右+ (1 f - positionOffset) * targetRight); } 返回新Pair<祝辞(targetLeft targetRight); } 私人Pair<浮动,Float>getIndicatorLeftRight(视图选项卡){ 左浮动=tab.getLeft (); 浮动对=tab.getRight (); 如果(indicatorMode==indicatorMode。包装,,选项卡instanceof TextView) { TextView tabTextView=(TextView)选项卡; paint.setTextSize (tabTextView.getTextSize ()); .toString浮动textLength=paint.measureText (tabTextView.getText () ()); 浮动中间=f(左+右)/2; 左=中等textLength/2 f; 正确的中产+ textLength/2=f; } 返回新Pair<祝辞(左、右); } >之前上面是计算下划线位置的代码,通过传入在onPageScrolled()中获得的位置和positionOffset,计算下划线是在某一个标签下,或者某两个标签之间的位置。需要注意的是,由于各标签的长度可能不一,所以下划线的长度在滑动中也可能发生变化,所以需分别计算下划线的左和右。
私人布尔isAnimateRunning=false; 私有静态最终字符串TARGET_LEFT=皌argetLeft”; 私有静态最终字符串TARGET_RIGHT=皌argetRight”; 私人空间startIndicatorAnimate(最后targetLeft浮动,最终浮targetRight) {//在指标超出屏幕范围时,让其从屏幕边界处开始移动 漂浮移动=0; 如果(indicatorCurrentRight & lt;getScrollX ()) { 移动=getScrollX () - indicatorCurrentRight; }else if (indicatorCurrentLeft比;getScrollX () + DimenUtil.getScreenWidth (getContext ())) { 移动=getScrollX () + DimenUtil.getScreenWidth (getContext ()) - indicatorCurrentLeft; } indicatorCurrentLeft +=移动; indicatorCurrentRight +=移动; PropertyValuesHolder valuesHolderLeft=PropertyValuesHolder.ofFloat ( TARGET_LEFT、indicatorCurrentLeft targetLeft); PropertyValuesHolder valuesHolderRight=PropertyValuesHolder.ofFloat ( TARGET_RIGHT、indicatorCurrentRight targetRight); ValueAnimator动画=ValueAnimator。ofPropertyValuesHolder (valuesHolderLeft valuesHolderRight) .setDuration (SCROLL_DURATION); 动画师。addUpdateListener(新ValueAnimator.AnimatorUpdateListener () { @Override 公共空间onAnimationUpdate (ValueAnimator动画){ 如果(indicatorCurrentLeft !=targetLeft) { indicatorCurrentLeft=(浮动)animation.getAnimatedValue (TARGET_LEFT); } 如果(indicatorCurrentRight !=targetRight) { indicatorCurrentRight=(浮动)animation.getAnimatedValue (TARGET_RIGHT); } 如果(indicatorCurrentLeft==targetLeft,,indicatorCurrentRight==targetRight) { isAnimateRunning=false; } 无效(); } }); animator.start (); isAnimateRunning=true; }Android实现网易严选标签栏滑动效果