国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

android使用Ultra-PullToRefresh實(shí)現(xiàn)下拉刷新自定義代碼

2019-10-23 19:46:30
字體:
供稿:網(wǎng)友

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

ultrapulltorefresh刷新,pulltorefresh,刷新,ultrapulltorefresh

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

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

ultrapulltorefresh刷新,pulltorefresh,刷新,ultrapulltorefresh

但是,這里考慮到這里L(fēng)ayout修改后可能會導(dǎo)致的下拉刷新原本功能的一系列問題,想想還是直接放棄。

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

<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實(shí)現(xiàn)PtrUIHandler的回調(diào)。其中用到的幾張圖片

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

ultrapulltorefresh刷新,pulltorefresh,刷新,ultrapulltorefresh

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

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

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

下拉刷新的距離以及狀態(tài)判斷處理在onUIPositionChange回調(diào)方法中

@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 {         //未觸發(fā)下拉刷新時拉著玩         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 {           //下拉距離已經(jīng)達(dá)到了可以觸發(fā)下拉刷新的位置。使用圖片2           drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_1);           flag = 2;         }       }     } else {       //當(dāng)前正在下拉刷新的時候.自己手動去滑動圖片不做變化       flag = 3;       if (!animation.isHasStart()) {         startAnimation(animation);         animation.setHasStart(true);       }     }     invalidate();   } 

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

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

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

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; 

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

ultrapulltorefresh刷新,pulltorefresh,刷新,ultrapulltorefresh

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

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

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

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

圖片循環(huán)輪播,計算好圖片位置與時間間隔,定時切換圖片

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自身帶有一個參數(shù)mDurationToClose,可以理解為放手后界面回彈到刷新高度所預(yù)留的時間,可以在這個時間內(nèi)對顯示做些優(yōu)化。在這里我根據(jù)這個時間值做了弧線緩慢上彈的動畫。

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);       //設(shè)置動畫結(jié)束后保留效果        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中對應(yīng)的顯示

case 3:         //正在刷新時,執(zhí)行彈上去的動畫         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圖不清晰的話可以將代碼下載下來自己運(yùn)行,可以將該部分注釋后對比兩種效果,對比還是蠻明顯的。

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.初始狀態(tài),未下拉或者下拉高度未達(dá)到繪制弧線的高度

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方法就完成了,其中關(guān)于圖片繪制與顯示位置的計算費(fèi)了不少腦細(xì)胞。然后在代碼中添加上PtrFrameLayout的配置即可使用

ultrapulltorefresh刷新,pulltorefresh,刷新,ultrapulltorefresh

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

代碼下載地址:TestUltraPullToRefresh.rar

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 张掖市| 镇远县| 赣州市| 长宁区| 通江县| 股票| 噶尔县| 万山特区| 思南县| 固安县| 化州市| 沂南县| 登封市| 海阳市| 德州市| 孟村| 勐海县| 商城县| 宁武县| 天水市| 丹江口市| 海宁市| 浦东新区| 成都市| 延寿县| 云霄县| 宁海县| 嘉祥县| 崇明县| 涞源县| 临漳县| 剑河县| 桃源县| 来宾市| 宁阳县| 河源市| 安乡县| 渝中区| 江孜县| 焉耆| 越西县|