中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

Android實現網易嚴選標簽欄滑動效果

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

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

Android實現網易嚴選標簽欄滑動效果

網易嚴選的標簽欄就做的很不錯,里面隱藏著諸多細節:

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

仔細分析下,需要在簡單標簽欄的基礎上實現以下邏輯:

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

Android實現網易嚴選標簽欄滑動效果

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

// 根據當前選定的tab,得到indicator應該移動到的位置 
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之間,需進行加權計算得到它的位置 
  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,計算下劃線是在某一個標簽下,或者某兩個標簽之間的位置。需要注意的是,由于各標簽的長度可能不一,所以下劃線的長度在滑動中也可能發生變化,所以需分別計算下劃線的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; 
} 

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

更多的細節,請見https://github.com/wlkdb/page_sliding

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宝丰县| 博野县| 阳新县| 许昌市| 阳春市| 鹰潭市| 呼伦贝尔市| 北碚区| 泾川县| 呼玛县| 高雄市| 名山县| 岗巴县| 湄潭县| 防城港市| 民县| 运城市| 宝应县| 尖扎县| 柘城县| 耒阳市| 松桃| 麻城市| 白朗县| 云龙县| 广平县| 康乐县| 庄浪县| 泗水县| 娄烦县| 孝义市| 叶城县| 威宁| 黑河市| 葵青区| 三台县| 宿州市| 龙江县| 临潭县| 横峰县| 称多县|