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

时间:2022-01-03 10:21:08
需求描述

最近项目中有这样一个需求,页面有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;

}
});

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