Android_滚动状态ScrollView实现标题的悬浮和渐隐

来源:互联网 发布:1325雕刻机参数算法 编辑:程序博客网 时间:2024/05/26 12:04

最近项目需求,需要实现标题的悬浮和渐隐渐变….于是故事开始了

1,代码接受后,业务逻辑复杂,最好的完成就是基于现在XML和activity 做最少的改动实现,所以网上的demo,以及5.0后的Coordinglayout 我就放弃了,这样的改动及时能实现,也要改太多东西,

2,于是还是自己实现下吧,下图是预览,GIF 录制不了..哎
上滑动的时候titlebar 渐出
下滑动的时候titlebar 渐入

这里写图片描述

这里是初始进入的样子

这里写图片描述

这里是慢慢画出的样子

这里写图片描述

这里是全部画出的样子
这里写图片描述

最后是渐入的样子,

==========================================================
OK,基于不是自己实现的代码,最加单的实现就是改变最外层布局为FrameLayout + include进来titlebarbar

初始化的时候把titlebar隐藏,注意这里的隐藏不是GONE掉,而是把titlebar设置到屏幕外面,很简单,大家都会,这里就不浪费时间描述了

发现短短的三句代码不到 我们的功能已经实现了一半了对不对

首先描述下实现思路

  • 根据现在的代码状态,基于scrollview的滑动,改变titlebar的位置
  • 由于scrollview给我们提供了一个私有的onScrollChanged方法,注意
    如果你用AS自己设置一个onScrollChanged方法,会提示你,低版本的API不能用而且会crash,所以我们自己重写scrollview 提供接口给外界activity用
  • 然后我们重写scrollview的ontouch方法,模拟出scrollview的滑动状态
    public interface OnScrollListener {        int SCROLL_STATE_IDLE = 0;        int SCROLL_STATE_TOUCH_SCROLL = 1;        int SCROLL_STATE_FLING = 2;        void onBottomArrived();        void onScrollStateChanged(ATListenedScrollView view, int scrollState);        void onScrollChanged(int l, int t, int oldl, int oldt);    }

这里是ontouch方法

 @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:            case MotionEvent.ACTION_MOVE:                inTouch = true;                break;            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:                inTouch = false;                lastT = getScrollY();                checkStateHandler.removeMessages(CHECK_STATE);                checkStateHandler.sendEmptyMessageDelayed(CHECK_STATE, 5);                break;            default:                break;        }        return super.onTouchEvent(ev);    }

完整的scrollview 代码如下,直接用就可以获取 坐标的变化和scrollview的滑动状态

public class ATListenedScrollView extends ScrollView {    private static final int CHECK_STATE = 0;    private OnScrollListener onScrollListener;    private boolean inTouch = false;    private int lastT = 0;    public ATListenedScrollView(Context context) {        super(context);    }    public ATListenedScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public ATListenedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:            case MotionEvent.ACTION_MOVE:                inTouch = true;                break;            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:                inTouch = false;                lastT = getScrollY();                checkStateHandler.removeMessages(CHECK_STATE);                checkStateHandler.sendEmptyMessageDelayed(CHECK_STATE, 5);                break;            default:                break;        }        return super.onTouchEvent(ev);    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        super.onScrollChanged(l, t, oldl, oldt);        if (onScrollListener == null) {            return;        }        if (inTouch) {            if (t != oldt) {                onScrollListener.onScrollStateChanged(this,                        OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);            }        } else {            if (t != oldt) {                onScrollListener.onScrollStateChanged(this,                        OnScrollListener.SCROLL_STATE_FLING);                lastT = t;                checkStateHandler.removeMessages(CHECK_STATE);                checkStateHandler.sendEmptyMessageDelayed(CHECK_STATE, 5);            }        }        onScrollListener.onScrollChanged(l, t, oldl, oldt);    }    public void setOnScrollListener(OnScrollListener onScrollListener) {        this.onScrollListener = onScrollListener;    }    public interface OnScrollListener {        int SCROLL_STATE_IDLE = 0;        int SCROLL_STATE_TOUCH_SCROLL = 1;        int SCROLL_STATE_FLING = 2;        void onBottomArrived();        void onScrollStateChanged(ATListenedScrollView view, int scrollState);        void onScrollChanged(int l, int t, int oldl, int oldt);    }    private WeakRefHandler checkStateHandler = new WeakRefHandler(this);    /**     * WeakReference handler     */    static class WeakRefHandler extends Handler {        WeakReference<ATListenedScrollView> atListenedScrollViewWeakReference;        WeakRefHandler(ATListenedScrollView atListenedScrollView) {            atListenedScrollViewWeakReference = new WeakReference<ATListenedScrollView>(atListenedScrollView);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            ATListenedScrollView atListenedScrollView = atListenedScrollViewWeakReference.get();            if (atListenedScrollView.lastT == atListenedScrollView.getScrollY()) {                atListenedScrollView.onScrollListener.onScrollStateChanged(atListenedScrollView, OnScrollListener.SCROLL_STATE_IDLE);                if (atListenedScrollView.getScrollY() + atListenedScrollView.getHeight() >= atListenedScrollView.computeVerticalScrollRange()) {                    atListenedScrollView.onScrollListener.onBottomArrived();                }            }        }    }}

现在我们的scrollview都提供好了,工作又完成了2/3
剩下的代码就是activity里面的滑动监听,改变titlebar的位置,顺道加一个渐变动画soeasy

Duang 来了

    private void initTitleScroll() {        scrollView.setOnScrollListener(new ATListenedScrollView.OnScrollListener() {            @Override            public void onBottomArrived() {            //如果scrollview滚到底部并且是静止状态,显示titlebar                if (isIDLE) {                    hotelTitelViewLayoutParams.topMargin = 0;                    hotelTitelView.setLayoutParams(hotelTitelViewLayoutParams);                    hotelTitelView.setAlpha(1.F);                }            }            @Override            public void onScrollStateChanged(ATListenedScrollView view, int scrollState) {            // 给我们定义的是否是滚动和滑翔的状态变量赋值                isFilling = scrollState == SCROLL_STATE_FLING;                isIDLE = scrollState == SCROLL_STATE_IDLE;            }            @Override            public void onScrollChanged(int l, int y, int oldl, int oldY) {            // 滑动监听的回调,如果是静止状态,并且y是0,这时候隐藏titlebar                if (isIDLE && 0 == y) {                    hotelTitelViewLayoutParams.topMargin = -hotelTitleHeight;                    hotelTitelView.setLayoutParams(hotelTitelViewLayoutParams);                    hotelTitelView.setAlpha(0);                    return;                }                // 如果是滑动状态,并且titlebar的topmarin是0,显示titlebar                if (isFilling && hotelTitelViewLayoutParams.topMargin == 0) {                    hotelTitelView.setAlpha(1.F);                    return;                } else if (isFilling && hotelTitelViewLayoutParams.topMargin < 0) {                    hotelTitelViewLayoutParams.topMargin = -hotelTitleHeight;                    hotelTitelView.setAlpha(0);                    hotelTitelView.setLayoutParams(hotelTitelViewLayoutParams);                    return;                }//特殊情况判断完毕,这是在滑动的时候dy是偏移量,根据便宜量计算出titlebar的alpha值,和改变titlebar距离顶部的位置,ok到此全部实现,                int dY = oldY - y;                hotelTitelView.setAlpha(ATUtils.getAlphaScale(hotelTitleHeight - Math.abs(hotelTitelViewLayoutParams.topMargin), hotelTitleHeight));                if (hotelTitelViewLayoutParams.topMargin > 0) {                    hotelTitelViewLayoutParams.topMargin = 0;                    hotelTitelView.setLayoutParams(hotelTitelViewLayoutParams);                    return;                }                if (dY < 0 && hotelTitelViewLayoutParams.topMargin == 0) {                    // up slide edge                    return;                } else if (dY > 0 && hotelTitelViewLayoutParams.topMargin == -hotelTitleHeight) {                    // down slide edge                    return;                }                if (hotelTitelViewLayoutParams.topMargin >= -hotelTitleHeight && hotelTitelViewLayoutParams.topMargin <= 0) {                    hotelTitelViewLayoutParams.topMargin = hotelTitelViewLayoutParams.topMargin - dY;                } else if (hotelTitelViewLayoutParams.topMargin > 0) {                    hotelTitelViewLayoutParams.topMargin = 0;                } else if (hotelTitelViewLayoutParams.topMargin < -hotelTitleHeight) {                    hotelTitelViewLayoutParams.topMargin = -hotelTitleHeight;                }                hotelTitelView.setLayoutParams(hotelTitelViewLayoutParams);            }        });    }

关键代码和自定义的scrollview全部在这里,因为直接写项目里面的所以没有demo可上传,如果有类似效果直接copy上面代码即可

当有需求改变,但前期代码不是你自己的情况下,尽可能的做的改动最少来实现,尤其是业务逻辑部分,根本不用关心,只需要扩展即可,如果找github或者其他demo 如果是基于Coordinglayout等等,需要改变的就不是这么一点了

1 1