溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android實現(xiàn)網(wǎng)易嚴(yán)選標(biāo)簽欄滑動效果

發(fā)布時間:2020-10-13 00:13:46 來源:腳本之家 閱讀:208 作者:wlkdb 欄目:移動開發(fā)

標(biāo)簽欄是一個非常常見的控件,似乎也是一個比較簡單的控件,但如果在標(biāo)簽下方加個下劃線的話,就還是可以玩出挺多花來的。

Android實現(xiàn)網(wǎng)易嚴(yán)選標(biāo)簽欄滑動效果

網(wǎng)易嚴(yán)選的標(biāo)簽欄就做的很不錯,里面隱藏著諸多細(xì)節(jié):

  • 手動滑動頁面,下劃線會跟著滑動。
  • 選擇一個標(biāo)簽后,下劃線會有滑動過去的動畫。
  • 選擇最左端或最右端的標(biāo)簽,標(biāo)簽欄會進行滑動,使得標(biāo)簽向中間靠攏(如果可以滑的話)。

仔細(xì)分析下,需要在簡單標(biāo)簽欄的基礎(chǔ)上實現(xiàn)以下邏輯:

  • 畫出下劃線。
  • 監(jiān)聽手動滑動頁面事件,實時更新下劃線位置。
  • 切換標(biāo)簽時,開始下劃線滑動的動畫,并判斷是否要同時滑動標(biāo)簽欄。

Android實現(xiàn)網(wǎng)易嚴(yán)選標(biāo)簽欄滑動效果

我做了一個樣例程序,其中的較難點在于計算下劃線的位置,和下劃線的動畫效果。

// 根據(jù)當(dāng)前選定的tab,得到indicator應(yīng)該移動到的位置 
private Pair<Float, Float> getIndicatorTargetLeftRight(int position, float positionOffset) { 
  View tab = tabsContainer.getChildAt(position); 
  Pair<Float, Float> indicator = getIndicatorLeftRight(tab); 
  float targetLeft = indicator.first; 
  float targetRight = indicator.second; 
  // 如果positionOffset不為0,indicator正處于兩個tab之間,需進行加權(quán)計算得到它的位置 
  if (positionOffset > 0f && position < tabCount - 1) { 
    View nextTab = tabsContainer.getChildAt(position + 1); 
    Pair<Float, Float> indicatorForNextTab = getIndicatorLeftRight(nextTab); 
    float left = indicatorForNextTab.first; 
    float right = indicatorForNextTab.second; 
    targetLeft = (positionOffset * left + (1f - positionOffset) * targetLeft); 
    targetRight = (positionOffset * right + (1f - positionOffset) * targetRight); 
  } 
  return new Pair<>(targetLeft, targetRight); 
} 
 
private Pair<Float, Float> getIndicatorLeftRight(View tab) { 
  float left = tab.getLeft(); 
  float right = tab.getRight(); 
  if (indicatorMode == IndicatorMode.WRAP && tab instanceof TextView) { 
    TextView tabTextView = (TextView) tab; 
    paint.setTextSize(tabTextView.getTextSize()); 
    float textLength = paint.measureText(tabTextView.getText().toString()); 
    float middle = (left + right) / 2f; 
    left = middle - textLength / 2f; 
    right = middle + textLength / 2f; 
  } 
  return new Pair<>(left, right); 
} 

上面是計算下劃線位置的代碼,通過傳入在onPageScrolled()中獲得的position和positionOffset,計算下劃線是在某一個標(biāo)簽下,或者某兩個標(biāo)簽之間的位置。需要注意的是,由于各標(biāo)簽的長度可能不一,所以下劃線的長度在滑動中也可能發(fā)生變化,所以需分別計算下劃線的left和right。

private boolean isAnimateRunning = false; 
private static final String TARGET_LEFT = "targetLeft"; 
private static final String TARGET_RIGHT = "targetRight"; 
 
private void startIndicatorAnimate(final float targetLeft, final float targetRight) { 
  // 在indicator超出屏幕范圍時,讓其從屏幕邊界處開始移動 
  float move = 0; 
  if (indicatorCurrentRight < getScrollX()) { 
    move = getScrollX() - indicatorCurrentRight; 
  } else if (indicatorCurrentLeft > getScrollX() + DimenUtil.getScreenWidth(getContext())) { 
    move = getScrollX() + DimenUtil.getScreenWidth(getContext()) - indicatorCurrentLeft; 
  } 
  indicatorCurrentLeft += move; 
  indicatorCurrentRight += move; 
 
  PropertyValuesHolder valuesHolderLeft = PropertyValuesHolder.ofFloat( 
      TARGET_LEFT, indicatorCurrentLeft, targetLeft); 
  PropertyValuesHolder valuesHolderRight = PropertyValuesHolder.ofFloat( 
      TARGET_RIGHT, indicatorCurrentRight, targetRight); 
  ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(valuesHolderLeft, valuesHolderRight) 
      .setDuration(SCROLL_DURATION); 
  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
    @Override 
    public void onAnimationUpdate(ValueAnimator animation) { 
      if (indicatorCurrentLeft != targetLeft) { 
        indicatorCurrentLeft = (float) animation.getAnimatedValue(TARGET_LEFT); 
      } 
      if (indicatorCurrentRight != targetRight) { 
        indicatorCurrentRight = (float) animation.getAnimatedValue(TARGET_RIGHT); 
      } 
      if (indicatorCurrentLeft == targetLeft && indicatorCurrentRight == targetRight) { 
        isAnimateRunning = false; 
      } 
      invalidate(); 
    } 
  }); 
  animator.start(); 
  isAnimateRunning = true; 
} 

這是切換標(biāo)簽時下劃線運行滑動動畫的代碼,使用ValueAnimator實現(xiàn),并且對下劃線超出邊界的情況做了特殊處理,以防止滑動距離過大時,滑動速度過快。

更多的細(xì)節(jié),請見https://github.com/wlkdb/page_sliding

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI