美文网首页Android ZoneAndroid之界面
Android ScrollView实现标题栏渐变效果

Android ScrollView实现标题栏渐变效果

作者: 翻译不了的声响 | 来源:发表于2018-05-14 15:47 被阅读5次

    ScrollView 在我们平时开发中经常用到,它是将一些不确定高度的子组件装进确定高度的容器,允许显示比实际多的内容。有时候我们需要监听ScroView的滑动情况,比如滑动了多少距离,是否滑到布局的顶部或者底部等等。下面我们就来看一看通过监听纵向滑动距离,来实现标题栏渐变效果。

    效果图
    1. 实现方法

    ① 方法一:
    通过 View.OnScrollChangeListener 监听组件滑动变化

    scrollView.setOnScrollChangeListener(new OnScrollChangeListener() {
        @Override
        public void onScrollChange(View view, int l, int t, int oldl, int oldt) {       
            int mHeight = mTvTitle.getHeight();//获取标题栏高度
            if (t <= 0) {//未滑动
                mTvTitle.setBackgroundColor(Color.argb((int) 0, 31, 100, 240));
            } else if (t > 0 && t <= mHeight) { //滑动过程中 并且在mHeight之内
                float scale = (float) t / mHeight;
                float alpha = (255 * scale);
                mTvTitle.setTextColor(Color.argb((int) alpha, 255, 255, 255));
                mTvTitle.setBackgroundColor(Color.argb((int) alpha, 31, 100, 240));
            } else {//超过mHeight
                mTvTitle.setBackgroundColor(Color.argb((int) 255, 31, 100, 240));
            }
        }
    });
    

    注意:该方法是API 23才出来的,没有做向下兼容,所以在低版本使用会报错。

    ② 方法二:
    使用 ViewTreeObserver.OnScrollChangedListener 监听视图中的组件滑动变化

    scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int y = scrollView.getScrollY();//获取纵向滑动距离
            int mHeight = mTvTitle.getHeight();//获取标题栏高度
            if (y <= 0) {//未滑动
                mTvTitle.setBackgroundColor(Color.argb((int) 0, 31, 100, 240));
            } else if (y > 0 && y <= mHeight) { //滑动过程中 并且在mHeight之内
                float scale = (float) y / mHeight;
                float alpha = (255 * scale);
                mTvTitle.setTextColor(Color.argb((int) alpha, 255, 255, 255));
                mTvTitle.setBackgroundColor(Color.argb((int) alpha, 31, 100, 240));
            } else {//超过mHeight
                mTvTitle.setBackgroundColor(Color.argb((int) 255, 31, 100, 240));
            }
        }
    });
    

    注意:ViewTreeObserver.OnScrollChangedListener接口在视图中组件发生改变或者某个组件状态发生改变时,都会调用回调函数。所以可能会被多次触发,不需要用的时候记得移除监听scrollView.getViewTreeObserver().removeOnScrollChangedListener(this),否则可能会出现内存泄漏。

    ③ 方法三:
    通过 View.OnTouchListener 触摸监听来实现

    scrollView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction()==MotionEvent.ACTION_MOVE) {
                int y = scrollView.getScrollY();//获取纵向滑动距离
                int mHeight = mTvTitle.getHeight();//获取标题栏高度
                if (y <= 0) {//未滑动
                    mTvTitle.setBackgroundColor(Color.argb((int) 0, 31, 100, 240));
                } else if (y > 0 && y <= mHeight) { //滑动过程中 并且在mHeight之内
                    float scale = (float) y / mHeight;
                    float alpha = (255 * scale);
                    mTvTitle.setTextColor(Color.argb((int) alpha, 255, 255, 255));
                    mTvTitle.setBackgroundColor(Color.argb((int) alpha, 31, 100, 240));
                } else {//超过mHeight
                    mTvTitle.setBackgroundColor(Color.argb((int) 255, 31, 100, 240));
                }
            }
            return false;
        }
    });
    

    注意:该方法有个弊端,如果我们“用力滑动靠惯性让ScrollView自己滚动到底部或顶部”时,这种“惯性滑动”触摸事件是监听不到ScrollView滑动距离的,就会出现透明度显示错误的BUG。

    ④ 方法四:
    自定义scrollview 实现一个接口,重写 onScrollChanged(int x, int y, int oldx, int oldy)方法,在方法中调用接口。

    1)自定义scrollview 类和接口:

    public class MyScrollView extends ScrollView {
        private OnScrollChanged mOnScrollChanged;
        public MyScrollView(Context context) {
            this(context);
        }
    
        public MyScrollView(Context context, AttributeSet attrs) {
            this(context, attrs);
        }
    
        public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
            if (mOnScrollChanged != null)
                mOnScrollChanged.onScroll(l, t, oldl, oldt);
        }
    
        public void setOnScrollChanged(OnScrollChanged onScrollChanged) {
            this.mOnScrollChanged = onScrollChanged;
        }
    
        public interface OnScrollChanged {
            void onScroll(int l, int t, int oldl, int oldt);
        }
    
    }
    

    2)在方法中调用接口:

    scrollView.setOnScrollChanged(new OnScrollChanged() {
        @Override
        public void onScroll(View view, int l, int t, int oldl, int oldt) {     
            int mHeight = mTvTitle.getHeight();//获取标题栏高度
            if (t <= 0) {//未滑动
                mTvTitle.setBackgroundColor(Color.argb((int) 0, 31, 100, 240));
            } else if (t > 0 && t <= mHeight) { //滑动过程中 并且在mHeight之内
                float scale = (float) t / mHeight;
                float alpha = (255 * scale);
                mTvTitle.setTextColor(Color.argb((int) alpha, 255, 255, 255));
                mTvTitle.setBackgroundColor(Color.argb((int) alpha, 31, 100, 240));
            } else {//超过mHeight
                mTvTitle.setBackgroundColor(Color.argb((int) 255, 31, 100, 240));
            }
        }
    });
    

    注意:l:当前横向滑动距离;t:当前纵向滑动距离 ;oldl:之前横向滑动距离 ;oldt:之前纵向滑动距离

    2. 注意事项

    如果通过getHeight()获取标题栏或其他控件高度失败时,可以通过 ViewTreeObserver.OnGlobalLayoutListener 接口来监听获得。

    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mHeight = mTvTitle.getHeight();//获取标题栏高度
            scrollView.getViewTreeObserver().removeGlobalOnLayoutListener(this);//注销监听,防止内存泄漏
        }
    });
    

    注意:当获得正确的宽高后,记得移除这个监听,否则回调会多次执行,可能会出现内存泄漏。

    相关文章

      网友评论

        本文标题:Android ScrollView实现标题栏渐变效果

        本文链接:https://www.haomeiwen.com/subject/whtqdftx.html