根据滑动改变view的大小和位置

本文详细介绍了如何实现一个需求,即在页面中,titlebar下方的头像随着scrollview滑动进行缩放并最终停在titlebar上。通过分析问题,将图片放置在titlebar和平级位置,并监听scrollview的滑动事件来调整图片的大小和位置。通过onTouch和scrollChangeListener的结合使用,解决了滑动不流畅和快速滑动时的精确性问题,实现了流畅且精确的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求描述

最近项目中有这样一个需求,页面有titlebar和scrollowview两部分,在titlebar的下边有一个头像,随着scrollowview的滑动,头像要缩放到固定大小然后停留在titlebar上不动了。

问题分析

首先这个需求并不陌生,类似于悬浮按钮。但是不同的是有缩放。如果将这个图片放在scrollview中的话,随着scrollview的滑动,图片是从titlebar的下边走了,被titlebar遮盖了。所以说我们要把图片放在和titlebae,scrollview平级的位置上。通过对scrollowview的changelistener的监听来改变图片的位置和大小。

代码实现

投机取巧,通过改变padding的方式来改变view的位置和大小

scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                if(top <=0){
                    top = rl_userhead.getPaddingTop();
                    bottom = rl_userhead.getPaddingBottom();
                    right = rl_userhead.getPaddingRight();
                    titleHeight = DensityUtil.dip2px(MainActivity.this,44);
                    small_top = DensityUtil.dip2px(MainActivity.this,9);
                    small_bottom = DensityUtil.dip2px(MainActivity.this,55);
                    small_right = DensityUtil.dip2px(MainActivity.this,21);
                }
                Log.e("输出y:",String.valueOf(scrollY));
                Log.e("输出:",String.valueOf(scrollY/44.0));

                if(scrollY<=0){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),top,right,bottom);
                }else if(scrollY>0 && scrollY<titleHeight){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),(int)(top-scrollY/44*35.0),(int)(right+ scrollY/44*21.0),(int)(bottom+ scrollY/44*55.0));
                }else {
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),small_top,small_right,small_bottom);
                }
            }
        });

首先需要分析默认情况下的位置,和最后需要固定的位置
下面的代码就是计算出默认情况下的padding和最后固定位置的padding

if(top <=0){
    top = rl_userhead.getPaddingTop();
    bottom = rl_userhead.getPaddingBottom();
    right = rl_userhead.getPaddingRight();
    titleHeight = DensityUtil.dip2px(MainActivity.this,44);
    small_top = DensityUtil.dip2px(MainActivity.this,9);
    small_bottom = DensityUtil.dip2px(MainActivity.this,55);
    small_right = DensityUtil.dip2px(MainActivity.this,21);
}

下边的代码是根据滑动的方向和距离来改变padding值

if(scrollY<=0){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),top,right,bottom);
                }else if(scrollY>0 && scrollY<titleHeight){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),(int)(top-scrollY/44*35.0),(int)(right+ scrollY/44*21.0),(int)(bottom+ scrollY/44*55.0));
                }else {
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),small_top,small_right,small_bottom);
                }
            }

ok,到了这里基本上算是完成了,运行看一下效果,比较满意。但是还有缺憾,感觉不是很流畅,有点卡顿。打印出来scrollY的值发现跨度比较大,还是int类型的。这样的话在计算的 过程中肯定要丢精度的。接下来就来优化一下。

优化效果

我们用onTouch来实现

scrollView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(motionEvent.getAction() == MotionEvent.ACTION_UP){
                    isInTouch = false;
                }
                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_MOVE){
                    isInTouch = true;
                }

                if(top <=0){
                    top = rl_userhead.getPaddingTop();
                    bottom = rl_userhead.getPaddingBottom();
                    right = rl_userhead.getPaddingRight();
                    titleHeight = DensityUtil.dip2px(MainActivity.this,44);
                    small_top = DensityUtil.dip2px(MainActivity.this,9);
                    small_bottom = DensityUtil.dip2px(MainActivity.this,55);
                    small_right = DensityUtil.dip2px(MainActivity.this,21);
                    //XgoLog.e("上下:"+top+"..."+bottom);
                }
                //XgoLog.e("上下:"+top+"..."+bottom);
                double y = scrollView.getScrollY();
                double s = y/44.0;

                Log.e("输出y:",String.valueOf(y));
                if(y<=0){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),top,right,bottom);
                }else if(y>0 && y<titleHeight){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),(int)(top-s*35.0),(int)(right+ s*21.0),(int)(bottom+ s*55.0));
                }else {
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),small_top,small_right,small_bottom);
                }

                return false;

            }
        });

代码不再解释了,运行效果非常流畅。但是又出现了另一个问题,快速滑动的时候可能不那么精确。我们先来想一下,onTouch是触摸的监听,当快速滑动的时候我们手指离开了屏幕,但是还在滑动,那手指离开了肯定就不会再执行onTouch了,自然图片也就不会动了。
前边也说了,虽然ontouch不再执行了,但是scrollow还在滑动呢,所以scrollChangeListener还在执行。我们的优化解决方案就是首先用onTouch来改变,当手指离开后用scrollChangeListener来接手改变view的位置。直接上代码

scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
            @Override
            public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {

                if(!isInTouch){
                    if(scrollY<=0){
                        rl_userhead.setPadding(rl_userhead.getPaddingLeft(),top,right,bottom);
                    }else if(scrollY>0 && scrollY<titleHeight){
                        rl_userhead.setPadding(rl_userhead.getPaddingLeft(),(int)(top-scrollY/44*35.0),(int)(right+ scrollY/44*21.0),(int)(bottom+ scrollY/44*55.0));
                    }else {
                        rl_userhead.setPadding(rl_userhead.getPaddingLeft(),small_top,small_right,small_bottom);
                    }
                }


            }
        });

        scrollView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(motionEvent.getAction() == MotionEvent.ACTION_UP){
                    isInTouch = false;
                }
                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_MOVE){
                    isInTouch = true;
                }

                if(top <=0){
                    top = rl_userhead.getPaddingTop();
                    bottom = rl_userhead.getPaddingBottom();
                    right = rl_userhead.getPaddingRight();
                    titleHeight = DensityUtil.dip2px(MainActivity.this,44);
                    small_top = DensityUtil.dip2px(MainActivity.this,9);
                    small_bottom = DensityUtil.dip2px(MainActivity.this,55);
                    small_right = DensityUtil.dip2px(MainActivity.this,21);
                    //XgoLog.e("上下:"+top+"..."+bottom);
                }
                //XgoLog.e("上下:"+top+"..."+bottom);
                double y = scrollView.getScrollY();
                double s = y/44.0;

                Log.e("输出y:",String.valueOf(y));
                if(y<=0){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),top,right,bottom);
                }else if(y>0 && y<titleHeight){
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),(int)(top-s*35.0),(int)(right+ s*21.0),(int)(bottom+ s*55.0));
                }else {
                    rl_userhead.setPadding(rl_userhead.getPaddingLeft(),small_top,small_right,small_bottom);
                }

                return false;

            }
        });

两个配合使用,效果完美。
完工!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值