当前位置:网站首页>另类实现 ScrollView 下拉头部放大
另类实现 ScrollView 下拉头部放大
2022-06-29 09:16:00 【禽兽先生不禽兽】
1 前言
前两天接到一个在列表下拉时头部放大的需求,也就是这样的效果:

2 思路
查了查资料,这样的效果一般都是通过自定义 ScrollView 来实现,不过我总觉得这样挺麻烦的,需要去修改原来的 XML 文件,而且局限性也挺大,需要缩放的控件必须放在第一个,在看了别人实现的思路(自定义scrollView实现顶部图片下拉放大)后,决定自己用一个工具类来实现这种效果。
在上面那位前辈的文章中他是自定义了一个 View 继承自 ScrollView,然后实现 onTouchListener 接口,重写 onTouch() 方法,在 onTouch() 方法中在做缩放的判断,所以说最重要的逻辑其实就是在 onTouch() 方法中。既然如此,我们其实只需要拿到需要监测滚动的 ScrollView,然后给它设置一个 onTouchListener 即可,何必还要自定义一个 ScrollView 并修改原来的布局文件呢。
3 代码实现
/**
* Description:滚动缩放的工具类
* Created by 禽兽先生
* Created on 2018/10/22
*/
public class ScrollZoomUtil {
//控件原始高
private static int sZoomViewOriginWidth = 0;
//控件原始宽
private static int sZoomViewOriginHeight = 0;
//被监听的可滚动控件按下时的纵坐标
private static float sLastY = 0;
//是否开始缩放的标志位
private static boolean sStartZoom = false;
public static void scrollZoom(final View scrollView, final View zoomView) {
zoomView.post(new Runnable() {
@Override
public void run() {
//记录控件原始宽高
sZoomViewOriginWidth = zoomView.getMeasuredWidth();
sZoomViewOriginHeight = zoomView.getMeasuredHeight();
}
});
scrollView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//当被监听的可滚动控件已经滚动到顶部时才可以进行缩放,置标志位为 true,记录下按下的纵坐标
if (scrollView.getScrollY() == 0) {
sStartZoom = true;
sLastY = event.getY();
return true;
}
break;
case MotionEvent.ACTION_MOVE:
if (sStartZoom) {
//计算滑动的距离
float distanceY = event.getY() - sLastY;
if (distanceY > 0) {
//当滑动距离大于 0 时表示下拉操作,对需要缩放的控件进行放大操作
zoom(zoomView, distanceY);
} else {
//当滑动距离小于 0 时表示上拉操作,判断需要缩放的控件的当前宽高,如果比原始宽高大则先缩放至原始宽高
if (zoomView.getMeasuredWidth() > sZoomViewOriginWidth) {
zoom(zoomView, distanceY);
} else {
//需要缩放的控件的当前宽高与原始宽高相等时再进行上拉,则进行正常的滚动操作
break;
}
}
return true;
}
case MotionEvent.ACTION_UP:
//手指抬起后恢复原始状态
sLastY = 0;
sStartZoom = false;
restore(zoomView);
break;
}
return false;
}
});
}
/**
* Description:缩放
* Date:2018/10/22
*/
private static void zoom(View zoomView, float distanceY) {
if (sZoomViewOriginWidth <= 0 || sZoomViewOriginHeight <= 0) {
return;
}
ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
//控件高为原始高度加上滑动距离乘以一个系数(与滑动距离 1:1 的话变化太大)
layoutParams.height = (int) (sZoomViewOriginHeight + distanceY * 0.4);
//控件宽等比例变化
layoutParams.width = (int) ((sZoomViewOriginWidth * (sZoomViewOriginHeight + distanceY * 0.4)) / sZoomViewOriginHeight);
zoomView.setLayoutParams(layoutParams);
}
/**
* Description:恢复成初始状态
* Date:2018/10/22
*/
private static void restore(final View zoomView) {
//利用属性动画恢复成原始宽高,使其有一个过渡效果
ValueAnimator widthValueAnimator = ObjectAnimator.ofInt(zoomView.getMeasuredWidth(), sZoomViewOriginWidth);
ValueAnimator heightValueAnimator = ObjectAnimator.ofInt(zoomView.getMeasuredHeight(), sZoomViewOriginHeight);
widthValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
layoutParams.width = (int) animation.getAnimatedValue();
zoomView.setLayoutParams(layoutParams);
}
});
heightValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
layoutParams.height = (int) animation.getAnimatedValue();
zoomView.setLayoutParams(layoutParams);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(widthValueAnimator).with(heightValueAnimator);
//这个动画时长是每个动画持续的时长而不是总时长
animatorSet.setDuration(300);
animatorSet.start();
}
}我在计算需要缩放的控件的宽高变化时比较粗糙,高度的变化就是滑动距离乘以一个系数,然后宽度等比例变化,不过效果看起来还行。使用的时候布局文件不用做任何改变:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_zoom"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitXY"
android:src="@drawable/img_1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:text="我是 TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:text="我是 TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:text="我是 TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:text="我是 TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:text="我是 TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="15dp"
android:text="我是 TextView" />
<ImageView
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitXY"
android:src="@drawable/img_2" />
</LinearLayout>
</ScrollView>
只需要在 Activity 中调用一下工具类传入一下需要检测和需要缩放的控件即可:
ScrollView scrollView = findViewById(R.id.scroll_view);
ImageView ivZoom = findViewById(R.id.iv_zoom);
ScrollZoomUtil.scrollZoom(scrollView, ivZoom);效果就是开头的那种效果。
4 总结
对于这种下拉缩放的需求,个人比较喜欢这种用一个外部方法来替代自定义 ScrollView 的方式,这样改动的地方比较小。条条大路通罗马,凡事多一种思考,现在做软件开发的话遇到什么需求,网上也许就已经有答案了,但其实最重要的还是要理解别人的思想,不然下次需求如果有点小变化自己还是搞不定。
边栏推荐
- Deep Learning-based Automated Delineation of Head and Neck Malignant Lesions from PET Images
- gSoap例子——calc
- 滑块验证代码
- leetcode MYSQL数据库题目177
- 自定义mvc框架实现
- Zabbix4.4 configure the indicators of the monitoring server and solve the garbled graphics pages
- C语言实现一种创建易管理易维护线程的方法
- 内网穿透工具frp使用入门
- [Huawei certification] the most complete and selected question bank in hcia-datacom history (with answer analysis)
- watch监听和computed计算属性的使用和区别
猜你喜欢

CROSSFORMER: A VERSATILE VISION TRANSFORMER BASED ON CROSS-SCALE ATTENTION

阿里云防火墙配置,多种设置方式(iptables和fireward)

【华为认证】HCIA-DATACOM史上最全精选题库(附答案解析)

Deep Learning-based Automated Delineation of Head and Neck Malignant Lesions from PET Images

Deep Learning-based Automated Delineation of Head and Neck Malignant Lesions from PET Images

How to traverse objects in the vector container

zabbix4.4配置监控服务器指标,以及图形页乱码解决

A 2.5D Cancer Segmentation for MRI Images Based on U-Net

Do you know what BFD is? This article explains the principle and usage scenarios of BFD protocol in detail

kdevelop新建工程
随机推荐
Install and configure redis in the Linux environment, and set the boot auto start
A method of creating easy to manage and maintain thread by C language
2020-09-25 boost库的noncopyable,用于单例模式
A 3D Dual Path U-Net of Cancer Segmentation Based on MRI
Kicad learning notes - shortcut keys
leetcode MYSQL数据库题目181
Leetcode MySQL database topic 180
遍历vector容器中的对象的方式
JVM之TLAB
Official STM32 chip package download address stm32f10x stm32f40x Download
JVM之对象的内存布局
Perfect binary tree, complete binary tree, perfect binary tree
Introduction to intranet penetration tool FRP
XML布局中Button总是在最上层显示
滑块验证代码
力扣94二叉树的中序遍历
JVM之 MinorGC、 MajorGC、 FullGC、
Invalidconnectionattributeexception exception exception handling
Data governance: Metadata Management (Part 2)
leetcode MYSQL数据库题目180