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

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

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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值