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

溫馨提示×

溫馨提示×

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

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

android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

發布時間:2020-09-29 21:30:24 來源:腳本之家 閱讀:346 作者:Yong_Alan 欄目:移動開發

下拉刷新中Ultra-Pull-To-Refresh一直是我最喜歡用的了,這里自定義一個HeaderView的樣式。和普通的樣式略微有些區別。先看效果圖

android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

一眼看上去和普通下拉刷新樣式沒啥區別,但仔細看會發現下拉時的頭部是蓋在內容上的(為了簡便,這里整個布局內容就一張圖片)。而PtrFrameLayout默認布局樣式是將header放置在內容上方,下拉時從上到下逐漸顯示。要實現這種頭部覆蓋在屏幕內容上的效果就需要我們另外想辦法了。

方案1:修改庫文件的,將headerView的顯示位置放置在內容上方。由于PtrFrameLayout本身自己是一個ViewGroup,修改其中的onLayout的代碼即可實現該樣式

android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

但是,這里考慮到這里Layout修改后可能會導致的下拉刷新原本功能的一系列問題,想想還是直接放棄。

方案2:不修改庫文件,HeaderView的位置不變,只是將headerView的內容顯示到content上面。這樣的話HeaderView的內容顯示就超出了其自身邊界,聽說在布局上加上一句神奇的代碼可以實現,于是自己去嘗試了下,確實真的可以。所以就選擇方案2繼續研究。

<in.srain.cube.views.ptr.PtrFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:id="@+id/ptr_layout_activity" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:clipChildren="false"> 

確定方案2后剩下的就是和普通自定義頭部差不多的步驟。自定義一個View實現PtrUIHandler的回調。其中用到的幾張圖片

首先觀察下拉刷新的過程可以知道,整個下拉刷新過程中的幾種狀態。

android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

狀態1:開始下拉時底部顯示弧線,黃色小人眼睛閉著(左1圖片),此時下拉的高度不足以觸發刷新操作;

狀態2:下拉到可以觸發刷新操作的高度后眼睛睜開(左2圖片);

狀態3:松手后刷新過程中的動作,動作由后面5張圖輪播切換顯示。

下拉刷新的距離以及狀態判斷處理在onUIPositionChange回調方法中

@Override 
  public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 
    //下拉距離 
    posY = ptrIndicator.getCurrentPosY(); 
    if (!isRefresh) { 
      if (isComplete) { 
        //剛剛完成了下拉刷新操作,還沒有重置事件。使用圖片2.保持上下邊距,下拉上推底部弧線不顯示 
        drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_1); 
        flag = 4; 
      } else { 
        //未觸發下拉刷新時拉著玩 
        if (posY < turning) { 
          //使用圖片1 
          drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_0); 
          flag = 0; 
        } else if (posY < measureHeight * RATIO_TO_REFRESH) { 
          //使用圖片1 
          //顯示下面的弧線 
          drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_0); 
          flag = 1; 
        } else { 
          //下拉距離已經達到了可以觸發下拉刷新的位置。使用圖片2 
          drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_1); 
          flag = 2; 
        } 
      } 
    } else { 
      //當前正在下拉刷新的時候.自己手動去滑動圖片不做變化 
      flag = 3; 
      if (!animation.isHasStart()) { 
        startAnimation(animation); 
        animation.setHasStart(true); 
      } 
    } 
    invalidate(); 
  } 

因為在等待刷新過程中也可以繼續滑動,為了刷新的正常顯示,這里添加了isRefresh(是否正在刷新)以及isComplete(是否刷新完成)的判斷。另外,由于最后刷新時保持顯示的是后面5張圖,因此控件高度的measureHeight需要與后面圖的大小有關,但是后面圖片小黃人的上下邊距太小,看上去視覺效果不太好,在設置measureHeight的時候特地增加了上下邊距

Drawable animationDrawable = ResourcesUtils.getDrawable(R.drawable.home_loading_2); 
measureHeight = padding * 2 + animationDrawable.getIntrinsicHeight(); 

準備工作就緒,接下來就是重點onDraw中的方法。根據不同的狀態繪制,但是這里有個麻煩的地方,上面7張圖中,小黃人大小是一樣的,但是后面5張圖周圍有了云朵背景,圖片整體比前兩張要大,所以在狀態切換時,圖片的繪制范圍需要格外注意。

1.繪制弧線階段,flag=1和2

switch (flag) { 
      case 1: 
      case 2: 
        controlY = (int) ((posY - turning) * RATIO_TO_REFRESH) > dragDistance * 2 
            ? dragDistance * 2 + measureHeight : (int) ((posY - turning) * RATIO_TO_REFRESH) 
            + measureHeight; 
        //下拉弧度 
        mPath.reset(); 
        mPath.moveTo(0, measureHeight); 
        mPath.quadTo(getWidth() / 2, controlY, getWidth(), measureHeight); 
        mPath.lineTo(getWidth(), 0); 
        mPath.lineTo(0, 0); 
        mPath.close(); 
 
        mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
            getBsrPositionY(controlY) - drawable.getIntrinsicHeight() * 2 / 3, 
            (canvas.getWidth() + drawable.getIntrinsicWidth()) / 2, 
            getBsrPositionY(controlY) + drawable.getIntrinsicHeight() / 3); 
 
        //繪制弧線 
        mPaint.setXfermode(null); 
        canvas.drawPath(mPath, mPaint); 
        canvas.save(); 
        canvas.clipPath(mPath); 
        drawable.setBounds(mDrawableRect); 
        drawable.draw(canvas); 
        canvas.restore(); 
        break; 

其中弧線是一條二階貝塞爾曲線。

android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

代碼中controlY為控制點P1的Y坐標,turning值表示下拉多少距離后開始繪制弧線(可以修改值來看看效果)。在這里我們的控制點X坐標在屏幕的中心(t=0.5),P0和P2的X坐標也是確定的,只需要求得對應的曲線Y軸最高點即可。又因為P0和P2Y軸坐標相同,都為measureHeight,所以這里二階曲線的最高點左邊簡化計算為

/** 
   * 獲取貝塞爾曲線最高點位置 
   * 
   * @param y 中間控制點的y坐標 
   * @return 
   */ 
  private int getBsrPositionY(int y) { 
    //起點和終點確定的 
    return measureHeight + (y - measureHeight) / 2; 
  } 

采用clipPath方式裁剪畫布,使得圖片按弧線顯示部分。

2.放手后開始刷新階段,flag = 3

圖片循環輪播,計算好圖片位置與時間間隔,定時切換圖片

mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
              padding, 
              (getWidth() + drawable.getIntrinsicWidth()) / 2, 
              padding + drawable.getIntrinsicHeight()); 
          if (drawable != null) { 
            drawable.setBounds(mDrawableRect); 
            drawable.draw(canvas); 
          } 
          if (SystemClock.elapsedRealtime() - lastTime > DURATION) { 
            //超過間隔后刷新動畫 
            changeDrawable(); 
            lastTime = SystemClock.elapsedRealtime(); 
          } 

但是在這里顯示上如果松手,弧線會立馬消失,顯示上不太友好。不過PtrFrameLayout自身帶有一個參數mDurationToClose,可以理解為放手后界面回彈到刷新高度所預留的時間,可以在這個時間內對顯示做些優化。在這里我根據這個時間值做了弧線緩慢上彈的動畫。

class MyAnimation extends Animation { 
 
    boolean hasStart; 
 
    public boolean isHasStart() { 
      return hasStart; 
    } 
 
    public void setHasStart(boolean hasStart) { 
      this.hasStart = hasStart; 
    } 
 
    @Override 
    public void initialize(int width, int height, int parentWidth, int parentHeight) { 
      super.initialize(width, height, parentWidth, parentHeight); 
      setDuration(mDurationToClose); 
      //設置動畫結束后保留效果 
 
      setInterpolator(new AccelerateDecelerateInterpolator()); 
    } 
 
    @Override 
    protected void applyTransformation(float interpolatedTime, Transformation t) { 
      super.applyTransformation(interpolatedTime, t); 
      //從0-1.逐漸變化(弧線回彈動畫),位置從controlY到0變化 
      flag = 3; 
      proportion = interpolatedTime; 
      invalidate(); 
    } 
  } 

 在onDraw中對應的顯示

case 3: 
        //正在刷新時,執行彈上去的動畫 
        if (proportion < 1.0f) { 
          mPath.reset(); 
          mPath.moveTo(0, measureHeight); 
          mPath.quadTo(getWidth() / 2, (controlY - measureHeight) * (1 - proportion) + measureHeight, getWidth(), measureHeight); 
          mPath.lineTo(getWidth(), 0); 
          mPath.lineTo(0, 0); 
          mPath.close(); 
          canvas.drawPath(mPath, mPaint); 
          mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
              (int) ((getBsrPositionY((int) controlY) - drawable.getIntrinsicHeight() - padding) * (1 - proportion)) + padding, 
              (getWidth() + drawable.getIntrinsicWidth()) / 2, 
              (int) ((getBsrPositionY((int) controlY) - (padding + drawable.getIntrinsicHeight())) * (1 - proportion)) + (padding + drawable.getIntrinsicHeight())); 
          if (drawable != null) { 
            drawable.setBounds(mDrawableRect); 
            drawable.draw(canvas); 
          } 
        } else {..} 

具體效果如果看上面gif圖不清晰的話可以將代碼下載下來自己運行,可以將該部分注釋后對比兩種效果,對比還是蠻明顯的。

3.刷新完成后還原的過程

case 4: 
        //刷新完成后,圖片此時換成了1,變小了。也要保持圖片的居中 
        mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
            (measureHeight - drawable.getIntrinsicHeight()) / 2, 
            (getWidth() + drawable.getIntrinsicWidth()) / 2, 
            (measureHeight + drawable.getIntrinsicHeight()) / 2); 
        if (drawable != null) { 
          drawable.setBounds(mDrawableRect); 
          drawable.draw(canvas); 
        } 
        break; 

4.初始狀態,未下拉或者下拉高度未達到繪制弧線的高度

case 0: 
    default: 
        //圖片位置 
        mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
            measureHeight - drawable.getIntrinsicHeight(), 
            (getWidth() + drawable.getIntrinsicWidth()) / 2, 
            measureHeight); 
        if (drawable != null) { 
          drawable.setBounds(mDrawableRect); 
          drawable.draw(canvas); 
        } 
        break; 

到這里整個onDraw方法就完成了,其中關于圖片繪制與顯示位置的計算費了不少腦細胞。然后在代碼中添加上PtrFrameLayout的配置即可使用

android使用Ultra-PullToRefresh實現下拉刷新自定義代碼

這些配置屬性也可以寫在xml中,下拉刷新的自定義基本就完成了。不過別高興太早,在繪制弧線的時候封閉區域采用了顏色填充,這個填充顏色就是paint的顏色,這個顏色要和跟布局顏色保持一致,不然自己試試看,這里我沒有給PtrFrameLayout設置背景色,而是采用了Theme,設置windowBackground的顏色。具體的代碼里面也有,就不繼續貼了,反正如果不設一樣的話你看上去會有bug。

代碼下載地址:TestUltraPullToRefresh_jb51.rar

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

向AI問一下細節

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

AI

吉隆县| 留坝县| 三原县| 仪征市| 罗平县| 本溪| 轮台县| 承德县| 沙坪坝区| 托克托县| 武山县| 涟源市| 河西区| 聂荣县| 绥棱县| 新安县| 道真| 侯马市| 舟山市| 南城县| 怀安县| 定陶县| 建瓯市| 肥西县| 香河县| 军事| 定远县| 会宁县| 嵊泗县| 乌兰察布市| 张掖市| 镇原县| 焦作市| 古田县| 马山县| 江源县| 鲁甸县| 长海县| 海口市| 石楼县| 乾安县|