美文网首页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