十分鐘學會定制 Android 酷炫下拉刷新。

這次UI又腦洞大開,嫌棄我們項目中的 SwipeRefreshLayout 的下拉效果沒特色,整了一個帶主題色彩的下拉刷新,效果圖如下:

想到又要手擼一個下拉刷新,心里頓時上萬條草泥馬奔騰。做為一只傲嬌程序猿,我們怎么能干出這種吃力不討好的事呢(邏輯判斷、Touch事件分發(fā)、狀態(tài)變化寫起來很麻煩,還特么可能有一大堆八阿哥)。吃口屎冷靜了一下,先分析吧~

要實現(xiàn)這個下拉刷新,主要的難點有:

1、下拉刷新功能的實現(xiàn)

2、刷新過程中的 UI 動效

3、 Demo 寫出來了,要是一個一個頁面去移植這個下拉刷新,那又得花不少時間,怎樣更快捷的方式替換掉項目中幾十上百個頁面。

解決思路:

難點一:說的下拉刷新的功能實現(xiàn),很多小伙伴都會說PullToRefreshListview、SwipeRefreshLayout呀,度娘一搜一大把。對,沒錯,我也是直接在 SwipeRefreshLayout 這個類上修改了刷新 Ui 效果。至于為什么不用PullToRefreshListview,因為我們項目中還有很多頁面并不是列表頁,但是也需要刷新。

難點二:刷新過程中的 UI 動效,這個后文我會帶著大家分析代碼實現(xiàn)。

難點三:全局搜索替換,把“android.support.v4.widget.SwipeRefreshLayout”替換成你的控件名就好,注意接口回調(diào)以及方法名和SwipeRefreshLayout保持一致即可。

好了,問題都已經(jīng)分析完了,接下來就擼代碼吧~

難點一解決:我的解決方案是直接修改了SwipeRefreshLayout,但是由于公司的源碼不方便拿出來講解,這里我在 Github 上隨便搜了一個和SwipeRefreshLayout 功能一樣的?Github Demo 來作講解,最終實現(xiàn)效果不好有任何影響,希望大家不要介懷。

使用起來很簡單

在 需要刷新的 View 父節(jié)點用 RefreshLayout 包裹

<com.rongyi.diamond.pulltorefresh.RefreshLayout

android:id="@+id/refreshLayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

<TextView

? ? android:layout_width="match_parent"

? ? android:layout_height="50dp"?

? ? android:background="#FFDAB9"

? ? android:gravity="center"

? ? android:text="Target"

? ? android:textSize="30sp"/>

</com.rongyi.diamond.pulltorefresh.RefreshLayout>

然后在 Java代碼中設(shè)置自定義的下拉刷新頭即可。

RefreshLayout refreshLayout=(RefreshLayout)findViewById(R.id.refreshLayout);

ShopView shopView=new ShopView(this)

refreshLayout.setRefreshHeader(shopView);

其中RefreshLayout就是GitHub 上面搜索的和SwipeRefreshLayout相似的類,ShopView 就是我自己寫的自定義下拉刷新樣式。

RefreshLayout 功能:攔截Touch 事件根據(jù)判斷子 View 是否滑動到頂部來判斷是否要顯示刷新頭,就是一個類似于RefreshLayout的容器。具體實現(xiàn)這里就不做重點講解了,有興趣的小伙伴自己自己下載下來讀一遍,源碼我會在文章結(jié)尾處貼出來。

ShopView:自定義的請求頭,難點二中會詳細講解ShopView的實現(xiàn)。

難點二解決:?

第一步:新建一個 ShopView 類,繼承RelativeLayout(繼承 ViewGroup 也行,我嫌棄麻煩),然后在構(gòu)造方面里面 View.inflate一個布局到當前 View。

第二步:讓布局里面的元素在合適的時候動起來

首先我們來分析刷新頭。動畫中的基本元素有:1.購物袋上的手提繩、2.“直擊全國專柜特賣現(xiàn)場”文字圖片、3.購物袋中噴出的商品、4.購物袋、

觀察 UI 效果圖我們發(fā)現(xiàn),購物袋需要在刷新的時候抖動、購物袋上的手提繩需要在下拉的過程中改變效果、刷新的時候購物袋中會噴出商品、刷新頭完整出現(xiàn)之后繼續(xù)下拉會出現(xiàn)“直擊全國專柜特賣現(xiàn)場”。

由于這些元素都包含在刷新頭里面,但是上面的4種動畫元素是需要根據(jù)不同的狀態(tài)來展示的,因此,我們需要一個接口來監(jiān)聽RefreshLayout中的狀態(tài)變化,這里原作者已經(jīng)提供了狀態(tài)回調(diào),我們直接用就行了。

public interface RefreshHeader{

/**

* 松手,頭部隱藏后會回調(diào)這個方法

*/

voidreset();

/**

* 下拉出頭部的一瞬間調(diào)用

*/

voidpull();

/**

* 正在刷新的時候調(diào)用

*/

voidrefreshing();

/**

* 頭部滾動的時候持續(xù)調(diào)用

*

* @paramcurrentPostarget當前偏移高度

* @paramlastPostarget上一次的偏移高度

* @paramrefreshPos可以松手刷新的高度

* @paramisTouch手指是否按下狀態(tài)(通過scroll自動滾動時需要判斷)

* @paramstate當前狀態(tài)

*/

voidonPositionChange(floatcurrentPos,floatlastPos,floatrefreshPos,booleanisTouch,RefreshLayout.Statestate);

/**

* 刷新成功的時候調(diào)用

*/

voidcomplete();

}

直接讓我們的 ShopView 實現(xiàn)這個接口,在相應(yīng)的狀態(tài)回調(diào)里面展示相應(yīng)的動畫即可。

接下來就只需要把這四個動畫擼出來就完成我們的定制下拉刷新了~

動畫一:手提繩的變化

首先,在onPositionChange()條目下拉的時候改變手提繩的效果。經(jīng)過觀察我們發(fā)現(xiàn)手提袋就是一個上下翻滾的效果,這里我們直接用一個二階貝塞爾曲線,起始點不動,控制點 x 軸在起始點正中間,y 軸根據(jù)onPositionChange()變化而變化即可。實現(xiàn)核心代碼如下:

@Override

public void onPositionChange(floatcurrentPos,floatlastPos,floatrefreshPos,booleanisTouch,RefreshLayout.Statestate){

mBezierLine.setControlY(currentPos);

}

這里直接把手提袋封裝了一個 View,setControlY方法實際上就是改變了控制點的 Y 軸,重新繪制了 View

public void setControlY(floaty){

if(isRefresh){

return;

}

if(y+min

control.y=y+min;

}else if(y+min>max&&y+min<2*(max-min)){

control.y=2*max-min-y;

}else{

control.y=min;

}

invalidate();

}

繪制代碼如下:

protected voidonDraw(Canvascanvas){

super.onDraw(canvas);

// 繪制貝塞爾曲線

mPaint.setColor(Color.WHITE);

mPaint.setStrokeWidth(2);

Pathpath=newPath();

path.moveTo(start.x,start.y);

path.quadTo(control.x,control.y,end.x,end.y);

canvas.drawPath(path,mPaint);

}


動畫二:當條目下拉過程中超過 刷新頭的高度時,改變“直擊全國專柜特賣現(xiàn)場”的setTranslationY即可

@Override

public void onPositionChange(floatcurrentPos,floatlastPos,floatrefreshPos,booleanisTouch,RefreshLayout.Statestate){

if(currentPos>mHeight){

inttranslationY=(int) (currentPos-mHeight);

intdp20=Utils.dp2px(getContext(),20);

if(translationY>dp20){

translationY=dp20;

}

mIvTrans.setTranslationY(dp20-translationY);

}else{

mIvTrans.setTranslationY(Utils.dp2px(getContext(),20));

}

}

動畫三:在刷新的回調(diào)中開啟噴出商品的動畫,在刷新結(jié)束的時候關(guān)閉即可

@Override

public voidrefreshing(){

star();

}

Handlerhandler=newHandler(){

@Override

public void handleMessage(Messagemsg){

super.handleMessage(msg);

addHeart();

handler.sendEmptyMessageDelayed(0,250);

}

};

public void star(){

handler.sendEmptyMessage(0);

}

說簡單點就是通過 handle 重復發(fā)送延時消息添加一個 shop,然后再展示一段動畫,最后在動畫結(jié)束的時候 remove 掉就好。addHeart()方面里面代碼量較多,具體實現(xiàn)代碼就不貼出來了。

動畫四:在刷新的回調(diào)中開啟購物袋抖動效果,在刷新結(jié)束的時候關(guān)閉即可。這里只是做了一個簡單的 Y軸縮放0.95的過程

ScaleAnimation scaleAnimation=new ScaleAnimation(1,1.0f,0.95f,1.0f,

Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);

scaleAnimation.setDuration(800);

scaleAnimation.setRepeatCount(100);//設(shè)置縮放次數(shù)

rongYi.startAnimation(scaleAnimation);


難點三解決:

此時,我們的下拉刷新 Demo 已經(jīng)完成了,測試沒問題之后就可以移植到項目中去了,傲嬌的程序員肯定不會選擇一個一個頁面去修改控件,那是代碼搬運工干的蠢事,我們直接全局搜索替換android.support.v4.widget.SwipeRefreshLayout就完工了,不會全局替換代碼的小伙伴自己去問一下度娘吧~


到這里,本次UI 提出的更換下拉刷新效果的需求已經(jīng)完成,再給大家回顧一次整個流程。首先拿到一個需求先不要慌,冷靜下來好好分析,分析完了之后也不要急著敲代碼,自己把整個思路再捋一遍,畫個草圖。最后,實際開發(fā)的過程中,能有現(xiàn)成的輪子可以用,就盡量利用,比如說這次的“難點一”,就直接用了現(xiàn)有的輪子。當然,時間充沛的前提下,自己造輪子也是可以的,這樣對自身的提高會比較有幫助。

我的夢想是“沒有bug”,感謝閱讀。

源碼在這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,613評論 25 708
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標下拉刷新...
    皇小弟閱讀 46,838評論 22 665
  • 今天早上閱讀我叔的《我的父親》知道有簡書這個日記方式。
    喜洋洋秀強閱讀 240評論 0 0
  • 快養(yǎng)成早起來的習慣了,只要睡覺在12點前就可以 注冊了百家號和頭條號,像百度這個流量王低頭
    鄭州鏈家芮培豪閱讀 140評論 0 1
  • 我不會承認的,大家的關(guān)注點全落在了她眉頭的兩點上了,淚奔~ 依然是沒時間看教程,純筆刷涂抹,抹得有點倉促,這次沒有...
    四月青閱讀 520評論 14 7