Android App的标题栏随ScrollView的滑动改变透明度

记录一下前一段时间做项目遇到的标题栏透明度随ScrollView的滚动变化问题的解决问题

描述:前几天项目里面有一个需求,就是根据ScrollView的滚动来设置标题栏的透明度,于是我就监听scrollView的setOnScrollChangeListener方法完成了,本来做好项目后没任何问题,但是回家后用一个4.4的手机测试发现奔了,打印后发现是由于ScrollView的setOnScrollChangeListener监听在Api23以上才可以使用,所以才导致的奔溃,解决办法很简单,就是自己写一个类MyScrollView,继承自ScrollView,在MyScrollView类里面重写onScrollChanged方法 即可实现,下面附上代码:
一、先实现类MyScrollView
public class MyScrollView extends ScrollView {
    private OnScrollChangeListener scrollChangeListener = null;
    public MyScrollView(Context context) {
        super(context);
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if (scrollChangeListener != null) {
            scrollChangeListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }
    public void setScrollViewListener(OnScrollChangeListener onScrollChangeListener) {
        this.scrollChangeListener = onScrollChangeListener;
    }

    public interface OnScrollChangeListener {
        void onScrollChanged(MyScrollView scrollView, int x, int y, int oldx, int oldy);
    }
 }
二、使用

在xml引用MyScrollView,然后在Activity里面通过findViewById()找到MyScrollView 调用setScrollViewListener方法

scrollView.setScrollViewListener(new MyOnScrollChangeListener());
/**
     * ScrollVoiew滑动监听
     */
    private class MyOnScrollChangeListener implements MyScrollView.OnScrollChangeListener {


        @Override
        public void onScrollChanged(MyScrollView, int x, int y, int oldx, int oldy) {
            //根据scrollview滑动更改标题栏透明度
            changeAphlaTitle(oldy, y);
        }
    }
    /**
     * 根据内容窗体的移动改变标题栏背景透明度
     *
     * @param startY scrollview开始滑动的y坐标(相对值)
     * @param endY   scrollview结束滑动的y坐标(相对值)
     */
    private void changeAphlaTitle(int startY, int endY) {
        //获取到状态栏的高度
        int statusBarHeight = getStatusBarHeight(mActivity);
        //获取标题高度
        int titleHeight = llTop.getLayoutParams().height;
        //获取背景高度
        int backHeight = DisplayUtil.dp2px(mActivity, 250);

        //获取控件的绝对位置坐标
        int[] location = new int[2];
        rlBgUnit.getLocationInWindow(location);
        //从屏幕顶部到控件顶部的坐标位置Y
        int currentY = location[1];
        //表示回到原位(滑动到顶部)
        if (currentY >= statusBarHeight) {
            llTop.setBackgroundColor(Color.argb(0, 0, 0, 0));
        }
        //顶部条目移除或移入屏幕的过程中;颜色透明度改变
        if (currentY < statusBarHeight && currentY >= -backHeight) {
            //计算出滚动过程中改变的透明值
            double changeValue = ((double) Math.abs(currentY) / (statusBarHeight + backHeight)) * 77;
            //判断是向上还是向下
            if (endY > startY) {//向上;透明度值增加,实际透明度减小
                llTop.setBackgroundColor(Color.argb((int) changeValue, 0, 0, 0));
            } else if (endY < startY) {//向下;透明度值减小,实际透明度增加
                llTop.setBackgroundColor(Color.argb((int) changeValue, 0, 0, 0));
            }
        }
        //顶部条目移除屏幕
        if (currentY < -backHeight) {
            llTop.setBackgroundColor(Color.argb(77, 0, 0, 0));
        }
    }

    /**
     * 获取通知栏高度
     *
     * @param context 上下文
     * @return 通知栏高度
     */
    private int getStatusBarHeight(Context context) {
        Class<?> c = null;
        Object obj = null;
        Field field = null;
        int x = 0, statusBarHeight = 0;
        try {
            c = Class.forName("com.android.internal.R$dimen");
            obj = c.newInstance();
            field = c.getField("status_bar_height");
            x = Integer.parseInt(field.get(obj).toString());
            statusBarHeight = context.getResources().getDimensionPixelSize(x);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return statusBarHeight;
    }
/**
     * 将dip或dp值转换为px值,保证尺寸大小不变
     *
     * @param dipValue (DisplayMetrics类中属性density)
     * @return
     */
    public static int dp2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现这个效果可以采用两种方案: 1. 使用 CoordinatorLayout 实现 CoordinatorLayout 是一个非常强大的布局容器,它可以协调多个子 View 的交互行为。在这个场景下,我们可以将标题栏作为 CoordinatorLayout 的直接子 View,将 ScrollView 作为标题栏的兄弟 View,然后使用 app:layout_behavior 属性指定标题栏的行为为 AppBarLayout.ScrollingViewBehavior,这样当 ScrollView 滑动时,标题栏就会自动滑动。 示例代码如下: ```xml <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:title="My Title" /> </com.google.android.material.appbar.AppBarLayout> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <!-- Your content here --> </ScrollView> </androidx.coordinatorlayout.widget.CoordinatorLayout> ``` 需要注意的是,这种方案需要使用 AndroidX 库中的 CoordinatorLayout 和 Material Design 组件库中的 AppBarLayout 和 MaterialToolbar。 2. 使用自定义 Behavior 实现 如果你不想使用 CoordinatorLayout,或者你需要实现一些比较特殊的效果,那么可以考虑使用自定义 Behavior 实现。具体来说,我们可以定义一个 Behavior,继承自 AppBarLayout.ScrollingViewBehavior,并重写 onNestedPreScroll 方法,在 ScrollView 滑动之前处理标题栏滑动。 示例代码如下: ```java public class MyBehavior extends AppBarLayout.ScrollingViewBehavior { public MyBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) { // 计算标题栏需要滑动的距离 int distance = Math.min(child.getHeight(), dy); // 滑动标题栏 child.setTranslationY(-distance); // 更新 consumed 数组,表示已经消耗了滑动距离 consumed[1] = distance; return true; } } ``` 然后在布局文件中将标题栏的 Behavior 设置为我们定义的 MyBehavior: ```xml <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_behavior=".MyBehavior"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:title="My Title" /> </com.google.android.material.appbar.AppBarLayout> ``` 需要注意的是,这种方案需要手动处理标题栏滑动,因此需要在 onNestedPreScroll 方法中计算标题栏需要滑动的距离,并使用 setTranslationY 方法滑动标题栏。同时,需要更新 consumed 数组,表示已经消耗了滑动距离,这样才能确保滑动事件正确地传递给 ScrollView

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值