用viewDragHelper來(lái)寫刷新控件<三>

前面第一章第二章講述了如何實(shí)現(xiàn)一個(gè)基本的上拉下拉控件,接下來(lái)討論一下里面關(guān)鍵的幾個(gè)類的實(shí)現(xiàn)以及如何增強(qiáng)功能

  • 工具類實(shí)現(xiàn)
  • 沒(méi)有數(shù)據(jù)時(shí)的空白頁(yè)面支持

ScrollViewCompat工具類

我們?cè)谏侠吕瓌?dòng)作的時(shí)候,需要通過(guò)ScrollViewCompat工具類來(lái)判斷是否達(dá)到頂端或者底端壤玫,一般可滑動(dòng)的控件分為ScrollView,ListView,WebViewRecyclerView询件,ListViewRecyclerView是通過(guò)當(dāng)前顯示的子視圖是否第一個(gè)或者最后一個(gè)以及是否有未顯示的視圖判斷缚忧,ScrollView是通過(guò)scrollY值判斷

/**
 * 該視圖控件還能否向下拉動(dòng)
 *
 * @param mTarget
 * @return true-未到頂部僵控,false-到頂部
 */
public static boolean canSmoothDown(View mTarget) {
    if (android.os.Build.VERSION.SDK_INT < 14) {
        if (mTarget instanceof AbsListView) {
            final AbsListView absListView = (AbsListView) mTarget;
            return absListView.getChildCount() > 0
                    && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                    .getTop() < absListView.getPaddingTop());
        } else if (mTarget instanceof RecyclerView) {
            final RecyclerView recyclerView = (RecyclerView) mTarget;
            LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
            if ((lm.findFirstVisibleItemPosition() == 0)) {
                View firstView = lm.findViewByPosition(0);
                return firstView.getTop() < 0;
            } else {
                return true;
            }
        } else {
            return mTarget.getScrollY() > 0;
        }
    } else {
        return ViewCompat.canScrollVertically(mTarget, -1);
    }
}

/**
 * 該視圖控件還能否向上拉動(dòng)
 *
 * @param mTarget
 * @return true-未到底部,false-到底部
 */
public static boolean canSmoothUp(View mTarget) {
    if (android.os.Build.VERSION.SDK_INT < 14) {
        if (mTarget instanceof AbsListView) {
            final AbsListView absListView = (AbsListView) mTarget;
            View lastChild = absListView.getChildAt(absListView.getChildCount() - 1);
            if (lastChild != null) {
                if (absListView.getFirstVisiblePosition() == 0 && absListView.getLastVisiblePosition() == (absListView.getCount() - 1)) {
                    return false;
                }
                return (absListView.getLastVisiblePosition() < (absListView.getCount() - 1))
                        && lastChild.getBottom() > absListView.getPaddingBottom();
            } else {
                return false;
            }
        } else if (mTarget instanceof RecyclerView) {
            final RecyclerView recyclerView = (RecyclerView) mTarget;
            LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
            int count = recyclerView.getAdapter().getItemCount() - 1;
            if (lm.canScrollVertically()) {
                return !(lm.findLastVisibleItemPosition() == count);
            } else {
                return false;
            }
        } else {
            View scrollChild = ((ViewGroup) mTarget).getChildAt(0);
            if (scrollChild == null) {
                return false;
            } else {
                int childHeight = scrollChild.getMeasuredHeight();
                return (mTarget.getScrollY() + mTarget.getHeight()) < childHeight;
            }
        }
    } else {
        return ViewCompat.canScrollVertically(mTarget, 1);
    }
}

空白頁(yè)面支持

一般在沒(méi)有數(shù)據(jù)的時(shí)候我們希望顯示一個(gè)缺省的空白頁(yè)面图柏,類似于ListViewemptyView

這里除了添加上空白頁(yè)面支持外序六,還需做一些小的改變。在顯示空白頁(yè)面時(shí)蚤吹,我們希望只有動(dòng)畫可拽動(dòng)而空白頁(yè)面不會(huì)被拽動(dòng)例诀,也就是侵入式的下拉效果(非侵入式效果即之前的正常列表的下拉)

    public DragRefreshLayout(Context context, AttributeSet attrs) {
        // .......
        emptyId = a.getResourceId(R.styleable.refresh_DragRefreshLayout_refresh_empty, 0);
        // .......
    }

    private void ensureTarget() {
        // .....
        if (emptyId != 0) {
            emptyView = findViewById(emptyId);
            emptyView.setClickable(true);
        }
    }

VDH的tryCaptureView中增加是否是emptyView的判斷

    @Override
    public boolean tryCaptureView(View child, int pointerId) {
        return child == mTarget
                || (child == emptyView && emptyView.isShown())
                || child == refreshView
                || child == loadView;
    }

不要忘了clampViewPositionVertical

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        if (child == mTarget || (child == emptyView && emptyView.isShown())) {
            status = ScrollStatus.DRAGGING;
            if (contentTop + dy > DRAG_MAX_RANGE) {
                return DRAG_MAX_RANGE;
            } else if (contentTop + dy < -DRAG_MAX_RANGE) {
                return -DRAG_MAX_RANGE;
            } else {
                return top;
            }
        } else {
            status = ScrollStatus.DRAGGING;
            if (contentTop + dy > DRAG_MAX_RANGE) {
                return DRAG_MAX_RANGE - refreshView.getMeasuredHeight();
            } else if (contentTop + dy < -DRAG_MAX_RANGE) {
                return getMeasuredHeight() - getPaddingBottom() - DRAG_MAX_RANGE;
            } else {
                return top;
            }
        }
    }

侵入式下拉即下拉時(shí)emptyView的位置不變,其他視圖的位置依然變化:

    @Override
    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
        if (changedView == mTarget) {
            //......
        } else if (changedView == emptyView && emptyView.isShown()) {
            refreshView.offsetTopAndBottom(dy);
            loadView.offsetTopAndBottom(dy);
            contentTop = top;
            invalidate();
        } else {
            // .......
        }
    }

因?yàn)榭丶痪S護(hù)數(shù)據(jù)內(nèi)容裁着,控件本身沒(méi)有設(shè)置空白頁(yè)面展示與隱藏的能力繁涂,不比ListView,因此只能在業(yè)務(wù)中判斷數(shù)據(jù)是否為空并且顯示或者隱藏空白頁(yè)面

到此二驰,整個(gè)DragRefresh控件完成扔罪,have a happy day!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市桶雀,隨后出現(xiàn)的幾起案子矿酵,更是在濱河造成了極大的恐慌,老刑警劉巖矗积,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件全肮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棘捣,警方通過(guò)查閱死者的電腦和手機(jī)辜腺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乍恐,“玉大人哪自,你說(shuō)我怎么就攤上這事〗” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵邑彪,是天一觀的道長(zhǎng)瞧毙。 經(jīng)常有香客問(wèn)我,道長(zhǎng)寄症,這世上最難降的妖魔是什么宙彪? 我笑而不...
    開(kāi)封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮有巧,結(jié)果婚禮上释漆,老公的妹妹穿的比我還像新娘。我一直安慰自己篮迎,他們只是感情好男图,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布示姿。 她就那樣靜靜地躺著,像睡著了一般逊笆。 火紅的嫁衣襯著肌膚如雪栈戳。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天难裆,我揣著相機(jī)與錄音子檀,去河邊找鬼。 笑死乃戈,一個(gè)胖子當(dāng)著我的面吹牛褂痰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播症虑,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缩歪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了侦讨?” 一聲冷哼從身側(cè)響起驶冒,我...
    開(kāi)封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎韵卤,沒(méi)想到半個(gè)月后骗污,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沈条,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年需忿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜡歹。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屋厘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出月而,到底是詐尸還是另有隱情汗洒,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布父款,位于F島的核電站溢谤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏憨攒。R本人自食惡果不足惜世杀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肝集。 院中可真熱鬧瞻坝,春花似錦、人聲如沸杏瞻。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至勉痴,卻和暖如春赫模,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蒸矛。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工瀑罗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雏掠。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓斩祭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親乡话。 傳聞我的和親對(duì)象是個(gè)殘疾皇子摧玫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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