用viewDragHelper来写刷新控件<三>

前面第一章第二章讲述了如何实现一个基本的上拉下拉控件,接下来讨论一下里面关键的几个类的实现以及如何增强功能

  • 工具类实现
  • 没有数据时的空白页面支持

ScrollViewCompat工具类

我们在上拉下拉动作的时候,需要通过ScrollViewCompat工具类来判断是否达到顶端或者底端,一般可滑动的控件分为ScrollView,ListView,WebViewRecyclerViewListViewRecyclerView是通过当前显示的子视图是否第一个或者最后一个以及是否有未显示的视图判断,ScrollView是通过scrollY值判断

/**
 * 该视图控件还能否向下拉动
 *
 * @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);
    }
}

/**
 * 该视图控件还能否向上拉动
 *
 * @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);
    }
}

空白页面支持

一般在没有数据的时候我们希望显示一个缺省的空白页面,类似于ListViewemptyView

这里除了添加上空白页面支持外,还需做一些小的改变。在显示空白页面时,我们希望只有动画可拽动而空白页面不会被拽动,也就是侵入式的下拉效果(非侵入式效果即之前的正常列表的下拉)

    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;
            }
        }
    }

侵入式下拉即下拉时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 {
            // .......
        }
    }

因为控件不维护数据内容,控件本身没有设置空白页面展示与隐藏的能力,不比ListView,因此只能在业务中判断数据是否为空并且显示或者隐藏空白页面

到此,整个DragRefresh控件完成,have a happy day!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容