Android下拉刷新, 頭在下方.

在開發(fā)中下拉刷新實在是一種常見的不能再覺的需求了, 網(wǎng)上也有很多優(yōu)秀的第三方框架鸽疾。不過之前有一個項目要求刷新的布局從下面出現(xiàn)而不是上面,因為沒有在網(wǎng)上找到合適的第三方庫所以就自己寫了一個demo训貌,在這里與大家分享一下制肮。

Demo

首先說實現(xiàn)思路:

  • 我們需要一個頭和身體且默認(rèn)是疊加在一起的.
  • 獲取這兩個View且最大滑動范圍為頭的高度.
  • 給身體設(shè)置滑動事件監(jiān)聽,改變身體的高度递沪,抬起時判斷是否刷新.
  • 提供一個方面豺鼻,可以動態(tài)改變是否下拉刷新.

上面最為麻煩的就是動態(tài)改變是否顯頭部,因為要解決事件沖突款慨,并不是每次手指下滑都代表用戶想刷新數(shù)據(jù)儒飒,這在ListView中很了解決,只需要判斷顯示的條目是否為是第一個就行檩奠,但在實際需求中可能只是一個普通的布局需要刷新桩了,而這里我們就無法得知下滑到底是顯示下面的數(shù)據(jù)還是刷新。在這里我用到了ViewDragHelper來解決這個問題埠戳。

效果實現(xiàn)及ViewDragHelper用法

第一步:寫一個類繼承FrameLayout使頭與身體疊加.

public class Luffy extends FrameLayout 

然后獲取頭和身體及其高度

@Override
    protected void onFinishInflate() {

        if(getChildCount() != 2)
            throw new IllegalStateException("只能有兩個子View");

        mContentView = getChildAt(1);
    }
------------------------------------------------------------
@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mHeight = getMeasuredHeight();
        mMaxDrag = (int) (mHeight * 0.2);
    }

onFinishInflate在布局文件加載完畢后調(diào)用井誉,我們可以在這里獲取到子類,onSizeChanged在測量完畢后會回調(diào)乞而,我們在這里獲取高度送悔,并設(shè)置最大拖拽范圍.

第二步:創(chuàng)建ViewDragHelper對象,該對象接收兩個參數(shù),分別為ViewGroupCallback欠啤,注意Callback是我們實現(xiàn)效果的關(guān)鍵類.并把觸摸事件和攔截事件交給ViewDragHelper.

ViewDragHelper.create(this, new RefurbishCallBack());
-------------------------------------------------------------
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }
-------------------------------------------------------------
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true; // 返回true觸發(fā)后續(xù)事件.
    }

Callback保有一個抽象方法tryCaptureView荚藻,該返回值決定了我們是否觸發(fā)拖拽事件,在這里我們觸發(fā)拖拽事件的條件有兩種洁段,觸摸View為Content和isRefurbish為true.當(dāng)我們觸摸的View是身體時并且isRefurbish為true時我們才允許刷新其他情況不觸發(fā).

/**
     * ViewDragHelper的回調(diào)方法
     */
    private class RefurbishCallBack extends ViewDragHelper.Callback{

        // 捕獲view
        @Override
        public boolean tryCaptureView(View child, int pointerId) {

            if(child == mContentView && isRefurbish){
                return true;
            }
            return isRefurbish;
        }

        // 限制view移動方式
        // 這里我們重寫的是clampViewPositionVertical方法应狱,當(dāng)我們縱向滑動時該方法調(diào)用
        // 并返回觸摸的View及移動大小
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {

            top = (int) (top * 0.93f); // 阻尼系數(shù)
            if(child == mContentView){
                 if(top < 0) top = 0;
            }
            return top;
        }

        // 釋放view時回調(diào),即抬手時
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {

            if(releasedChild != mContentView) return;
            // 判斷是否達(dá)到最大拖拽范圍, 達(dá)到則調(diào)用回調(diào)方法
            if(mContentView.getTop() >= mMaxDrag){
                onRefurbishListener.onRefurbish();                 
                scrollDown();
            }else {
                scrollUp();               
            }
        }

        // 這個方法比較重要祠丝,當(dāng)子view也需要事件時疾呻,重寫該方法并返回正數(shù),我這里返回的是觸發(fā)點(diǎn) 
        @Override
        public int getViewVerticalDragRange(View child) {
            return mMaxDrag;
        }

    }

核心代碼寫到這里就差不多了最后在提供一個方法改變isRefurbish值就可以達(dá)到動態(tài)刷新的目的.

public void isRefurbish(boolean isRefurbish){
  this.isRefurbish = isRefurbish;
}

下面是Activity中的代碼

luffy.setOnRefurbishListener(new RefurbishLayout.OnRefurbishListener() {
   @Override
  public void onRefurbish() {
       //加載數(shù)據(jù)...完畢后調(diào)用方法隱藏頭部
      refurbishLayout.setRefurbish(true);      
  }
};
--------------------------------------------------
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  // 根據(jù)第一個條目是否可見判斷開關(guān)刷新.
  refurbishLayout.isRefurbish(firstVisibleItem == 0);
}

點(diǎn)擊查看完成代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末写半,一起剝皮案震驚了整個濱河市岸蜗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叠蝇,老刑警劉巖璃岳,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異悔捶,居然都是意外死亡铃慷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門蜕该,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人堂淡,你說我怎么就攤上這事馋缅。” “怎么了绢淀?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵股囊,是天一觀的道長。 經(jīng)常有香客問我更啄,道長,這世上最難降的妖魔是什么居灯? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任祭务,我火速辦了婚禮,結(jié)果婚禮上怪嫌,老公的妹妹穿的比我還像新娘义锥。我一直安慰自己,他們只是感情好岩灭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布拌倍。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柱恤。 梳的紋絲不亂的頭發(fā)上数初,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機(jī)與錄音梗顺,去河邊找鬼泡孩。 笑死,一個胖子當(dāng)著我的面吹牛寺谤,可吹牛的內(nèi)容都是我干的仑鸥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼变屁,長吁一口氣:“原來是場噩夢啊……” “哼眼俊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粟关,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤疮胖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后誊役,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體获列,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年蛔垢,在試婚紗的時候發(fā)現(xiàn)自己被綠了击孩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹏漆,死狀恐怖巩梢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情艺玲,我是刑警寧澤括蝠,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站饭聚,受9級特大地震影響忌警,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜秒梳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一法绵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酪碘,春花似錦朋譬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽字柠。三九已至,卻和暖如春狡赐,著一層夾襖步出監(jiān)牢的瞬間窑业,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工阴汇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留数冬,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓搀庶,卻偏偏與公主長得像拐纱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哥倔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

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