Android实现图片点击预览效果(zoom动画)
发布时间 - 2026-01-11 00:17:12 点击率:次参考:https://developer.android.google.cn/training/animation/zoom.html

1.创建Views
下面的布局包括了你想要zoom的大版本和小版本的view。
1.ImageButton是小版本的,能点击的,点击后显示大版本的ImageView。
2.ImageView是大版本的,可以显示ImageButton点击后的样式。
3.ImageView一开始是不可见的(invisible),当ImageButton点击后,它会实现zoom动画,就像从ImageButton上扩大显示出来。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <ImageButton android:id="@+id/thumb_button_1" android:layout_width="100dp" android:layout_height="75dp" android:layout_marginRight="1dp" android:src="@drawable/thumb1" android:scaleType="centerCrop" android:contentDescription="@string/description_image_1" /> </LinearLayout> <!-- 这个不可见的ImageView持有上面的ImageButton zoom后的图片版本。 动画没有发生之前,它占据了整个屏幕。动画开始,这个View从上面 ImageButton的范围变化到他自己最终的范围。 --> <ImageView android:id="@+id/expanded_image" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" android:contentDescription="@string/description_zoom_touch_close" /> </FrameLayout>
2.设置zoom动画
在ImageButton上设置点击事件,执行zoom动画
public class ZoomActivity extends FragmentActivity {
// 保存下当前动画类,以便可以随时结束动画
private Animator mCurrentAnimator;
//系统的短时长动画持续时间(单位ms)
// 对于不易察觉的动画或者频繁发生的动画
// 这个动画持续时间是最理想的
private int mShortAnimationDuration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom);
// 给ImageButton设置点击事件
final View thumb1View = findViewById(R.id.thumb_button_1);
thumb1View.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//执行zoom动画方法
zoomImageFromThumb(thumb1View, R.drawable.image1);
}
});
//取回系统默认的短时长动画持续时间
mShortAnimationDuration = getResources().getInteger(
android.R.integer.config_shortAnimTime);
}
...
}
3.实现zoom动画
你需要把从正常大小的view到扩大以后的view这个过程作成动画。
1.指定想要zoom的图片给ImageView。(理想情况下,这个bitmap的大小不应该比屏幕大)
2.计算这个ImageView的开始和结束位置
3.把四个点和缩放大小的属性同时作成动画,从开始的状态到结束的状态。这四个动画被添加到AnimatorSet中,方便他们同时执行。
4.当用户再次点击屏幕时,动画要执行回去。一样道理,给ImageView一个View.OnClickListener,然后隐藏ImageView。
private void zoomImageFromThumb(final View thumbView, int imageResId) {
// 如果有动画在执行,立即取消,然后执行现在这个动画
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// 加载高分辨率的图片
final ImageView expandedImageView = (ImageView) findViewById(
R.id.expanded_image);
expandedImageView.setImageResource(imageResId);
// 计算开始和结束位置的图片范围
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
// 开始的范围就是ImageButton的范围,
// 结束的范围是容器(FrameLayout)的范围
// getGlobalVisibleRect(Rect)得到的是view相对于整个硬件屏幕的Rect
// 即绝对坐标,减去偏移,获得动画需要的坐标,即相对坐标
// getGlobalVisibleRect(Rect,Point)中,Point获得的是view在它在
// 父控件上的坐标与在屏幕上坐标的偏移
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container)
.getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
// Adjust the start bounds to be the same aspect ratio as the final
// bounds using the "center crop" technique. This prevents undesirable
// stretching during the animation. Also calculate the start scaling
// factor (the end scaling factor is always 1.0).
// 下面这段逻辑其实就是保持纵横比
float startScale;
// 如果结束图片的宽高比比开始图片的宽高比大
// 就是结束时“视觉上”拉宽了(压扁了)图片
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
// Extend start bounds horizontally
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
} else {
// Extend start bounds vertically
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
}
// Hide the thumbnail and show the zoomed-in view. When the animation
// begins, it will position the zoomed-in view in the place of the
// thumbnail.
// 隐藏小的图片,展示大的图片。当动画开始的时候,
// 要把大的图片发在小的图片的位置上
//小的设置透明
thumbView.setAlpha(0f);
//大的可见
expandedImageView.setVisibility(View.VISIBLE);
// Set the pivot point for SCALE_X and SCALE_Y transformations
// to the top-left corner of the zoomed-in view (the default
// is the center of the view).
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
// Construct and run the parallel animation of the four translation and
// scale properties (X, Y, SCALE_X, and SCALE_Y).
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X,
startBounds.left, finalBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y,
startBounds.top, finalBounds.top))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X,
startScale, 1f)).with(ObjectAnimator.ofFloat(expandedImageView,
View.SCALE_Y, startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
// Upon clicking the zoomed-in image, it should zoom back down
// to the original bounds and show the thumbnail instead of
// the expanded image.
// 再次点击返回小的图片,就是上面扩大的反向动画。即预览完成
final float startScaleFinal = startScale;
expandedImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator
.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.Y,startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
});
}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
# android图片点击预览
# android
# 点击预览图片
# android实现图片预览
# zoom动画
# Android仿京东顶部搜索框滑动伸缩动画效果
# Android实现页面滑动切换动画
# Android实现手势滑动和简单动画效果
# Android程序开发之使用Design包实现QQ动画侧滑效果和滑动菜单导航
# Android编程实现ViewPager多页面滑动切换及动画效果的方法
# Android Tween动画之RotateAnimation实现图片不停旋转效果实例介绍
# android实现图片闪烁动画效果的两种实现方式(实用性高)
# Android Glide图片加载(加载监听、加载动画)
# Android图片翻转动画简易实现代码
# Android实现ViewFlipper图片动画滑动
# 的是
# 持续时间
# 时长
# 就像
# 这段
# 要把
# 他自己
# 不应
# 它在
# 相对于
# 它会
# 可以随时
# 结束时
# 你想要
# 情况下
# 加载
# 压扁
# 占据了
# 屏幕上
# 这四个
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Android仿QQ列表左滑删除操作
如何在阿里云虚拟服务器快速搭建网站?
laravel怎么配置和使用PHP-FPM来优化性能_laravel PHP-FPM配置与性能优化方法
Laravel如何升级到最新版本?(升级指南和步骤)
海南网站制作公司有哪些,海口网是哪家的?
Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程
详解Android——蓝牙技术 带你实现终端间数据传输
Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】
如何挑选最适合建站的高性能VPS主机?
Windows10电脑怎么设置虚拟光驱_Win10右键装载ISO镜像文件
进行网站优化必须要坚持的四大原则
Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】
Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?
PythonWeb开发入门教程_Flask快速构建Web应用
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
Laravel如何实现API版本控制_Laravel版本化API设计方案
Laravel安装步骤详细教程_Laravel环境搭建指南
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
高端云建站费用究竟需要多少预算?
iOS发送验证码倒计时应用
Laravel如何实现模型的全局作用域?(Global Scope示例)
如何快速启动建站代理加盟业务?
深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?
高端网站建设与定制开发一站式解决方案 中企动力
在线制作视频网站免费,都有哪些好的动漫网站?
如何批量查询域名的建站时间记录?
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】
,怎么在广州志愿者网站注册?
Python并发异常传播_错误处理解析【教程】
宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法
如何挑选高效建站主机与优质域名?
Laravel用户密码怎么加密_Laravel Hash门面使用教程
Laravel如何使用模型观察者?(Observer代码示例)
三星网站视频制作教程下载,三星w23网页如何全屏?
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
linux写shell需要注意的问题(必看)
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工
利用 Google AI 进行 YouTube 视频 SEO 描述优化
ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法
Android自定义listview布局实现上拉加载下拉刷新功能
Python面向对象测试方法_mock解析【教程】
如何用PHP快速搭建高效网站?分步指南
Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】
Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康
谷歌Google入口永久地址_Google搜索引擎官网首页永久入口
在线教育网站制作平台,山西立德教育官网?

