android图片缩放模式,Android使用缩放动画放大你的图片
注:本篇文章是对官方开发文档的翻译,加上自己的理解和分析。
地址:https://developer.android.com/training/animation/zoom
本篇文章所实现的功能:
触摸一张ImageView后开始展示缩放动画,将视图从缩略图放大为填充屏幕的全尺寸图像,并且点击大图后还能够原路返回,缩放回去。无图无真相,先来看看效果图:
实现的代码中你需要知道的一些理论知识(大神请忽略):
首先是View的两个方法:
getGlobalVisibleRect(Rect r) → 得到这个view的可视区域的矩形
getGlobalVisibleRect(Rect r, Point globalOffset) → 比上面的那个多了个参数,这个参数的内容是view的左上角相对屏幕左上角的偏移量
一开始看到这我是有点迷糊的,getGlobalVisibleRect中第二个参数到底是干啥用的?抱着这个疑问,我决定打个Log来看看,先看看用了哪些代码来打印:
//下面这个container就是当前的根布局的id,finalBounds就是新建的一个Rect,
findViewById(R.id.container)
.getGlobalVisibleRect(finalBounds, globalOffset);
//globalOffset里的偏移量
Log.i("TAG", "globalOffset.x:" + globalOffset.x);
Log.i("TAG", "globalOffset.y:" + globalOffset.y);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
//获取状态栏高度
int height = 0;
int resourceId = getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
height = getApplicationContext().getResources().getDimensionPixelSize(resourceId);
}
Log.i("TAG", "状态栏高度:" + height);
//获取actionBar的高度
int actionBarHeight = 0;
TypedValue tv = new TypedValue();
if (this.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
Log.i("TAG", "actionBar高度:" + actionBarHeight);
}
打印的log:
到这里就一目了然了,根部局(也就是上面gif中白色的区域)的globalOffset.y = 状态栏高度 + actionBar高度 = 160,他们的关系就像下面这张图一样:
由于根部局container是铺满了除状态栏和actionBar之外的所有区域的,所以自然globalOffset.x就等于0了,这个不难理解。
在说完View的这两个方法之后,接下来开始进入正题,如何实现文章一开始时那个动图的效果呢?
1.在布局中准备一个ImageButton用于显示缩略图,再准备一个ImageView用于展示放大后的图片,一开始这个ImageView设置为不可见
2.给thumbView(ImageButton)设置点击事件,点击后开始放大,并将缩略图设置为invisible
public class MainActivity extends AppCompatActivity {
//动画的持续时间
private int mShortAnimationDuration = 1000;
//当前正在进行的动画
private AnimatorSet mCurrentAnimation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageButton thumbView = findViewById(R.id.ib_small);
thumbView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
zoomImageFromThumb(thumbView, R.mipmap.wang);
}
});
}
3.也就是核心部分,zoomImageFromThumb都做了哪些事儿,注释写的很清楚,大家先瞅瞅
/**
* 缩放动画
*
* @param thumbView 缩略图
* @param imageResId 图片资源ID
*/
private void zoomImageFromThumb(final View thumbView, int imageResId) {
//如果当前有动画就取消,并执行当前的动画
if (mCurrentAnimation != null) {
mCurrentAnimation.cancel();
}
//加载大图到预设好的ImageView中
final ImageView expandedImageView = findViewById(
R.id.iv_big);
expandedImageView.setImageResource(imageResId);
//计算放大图像的起始边界和结束边界
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
//起始边界是缩略图的全局可见矩形,最后的边界是容器container的全局可见矩形
//将容器视图container的偏移量设置为区域的起源,因为定位动画的起源属性是(X,Y)
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container)
.getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
//使用center_crop将起始边界调整为与最终边界相同的纵横比边界
//这可以防止在动画期间的不良拉伸。还计算开始缩放比例
float startScale;
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
//横向放大
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
} else {
//纵向放大
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
}
//隐藏缩略图并显示放大视图
//当动画开始时,它会将放大的视图定位在原来缩略图的位置
thumbView.setAlpha(0f);
expandedImageView.setVisibility(View.VISIBLE);
//设置SCALE_X和SCALE_Y转换的轴心点为到放大后视图的左上角(默认值是视图的中心)
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
//四种动画同时播放
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) {
mCurrentAnimation = null;
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimation = null;
}
});
set.start();
mCurrentAnimation = set;
//从这往下就是给大图设置点击监听,完成缩小回去的过程
final float startScaleFinal = startScale;
expandedImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCurrentAnimation != null) {
mCurrentAnimation.cancel();
}
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);
mCurrentAnimation = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimation = null;
}
});
set.start();
mCurrentAnimation = set;
}
});
}
除了注释之外,还需要对上面的代码做一些说明:
1.读了本文开头部分之后,相信你一定就明白了startBounds.offset()和finalBounds.offset();这两句话是在消除偏差,保证这两个矩形区域边界的计算都是相对于坐标轴的起始点(0,0)。
2.关于选择横向放大还是纵向放大的判断,先来看一张图:
就拿纵向放大来说吧,当startBounds的宽/高 > finalBounds的宽/高时,也就是上图右边那种情况,这时代码是下面这样的:
//纵向放大
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
经过上面几行代码的处理之后,实际上startBounds高度已经变高,相当将startBounds上下分别拉伸了相同距离,从而达到了纵向放大的效果。最终startBounds经过动画放大到红色区域,缩小的过程原理也是一样的,就不再多言了。
因为非常简单,所有代码已经贴在上面,所以就不贴demo了。
android图片缩放模式,Android使用缩放动画放大你的图片相关推荐
- android studio夜间模式,android studio怎样实现夜间模式
满意答案 noxlqub 2016.05.01 采纳率:51% 等级:7 已帮助:210人 关于阅读类的app,有个夜间模式真是太重要了. 那么有两种方式可以实现夜间模式 1:修改theme,重 ...
- android 省电模式,android省电模式设置
关于android省电模式设置技巧大全 一.屏幕显示 降低屏幕的亮度,可以有效的节省电能,尤其是摩托罗拉产的Android手机目前为止均为TFT屏幕,同时自动锁屏幕的时间设置的短一些也会带来一些电量的 ...
- android自动夜间模式,Android 夜间模式初探
当下各种阅读类APP(如各种浏览器,某日头条等)都会有夜间模式,也顺应了大家的睡前必须玩一下手机的作息习惯.关于夜间模式的实现,有很多种方法.这篇日志学习一下最简单的实现方式,通过setTheme(i ...
- Android自定义ImageView(二)——实现双击放大与缩小图片
效果图: 首先设置图片依据控件的大小来显示在ImageVeiw中 也就是当图片的宽与高小于控件的宽与高的时候,默认不进行对图片进行放大的操作,但是会将图片居中显示,当然使用的时候可以使用自定义的属性i ...
- android自动夜间模式,Android实现日夜间模式的深入理解
在本篇文章中给出了三种实现日间/夜间模式切换的方案,三种方案综合起来可能导致文章的篇幅过长,请耐心阅读. 1.使用 setTheme的方法让 Activity重新设置主题: 2.设置 Android ...
- android系统recovery模式,Android系统Recovery模式中文详细说明
Recovery具体功能: 1.刷系统:新下载好的rom,,直接放sd卡上刷(进nand),,无需windows! 2.像电脑的ghost,,允许用户随意将系统和里面的个人资料备份成一个文件,,并允许 ...
- android q 桌面模式,Android Q带来全新桌面模式
IT之家3月14日消息 谷歌在美国当地时间3月13日(北京时间14日凌晨)正式推送了Android Q的首个Beta版本,"亲儿子"Pixel系列全系手机可以尝鲜体验这最新的系统. ...
- android menu夜间模式,Android常用技巧夜间模式开发浅析
前言 Android的夜间模式主要主用于阅读方面,在QQ,微信读书,新闻阅读类一般会有相应的功能,本文主要介绍整体APP的夜间模式以及webview中夜间模式的实现. 效果图展示 功能实现简介 APP ...
- android l art模式,Android ART模式简介
Android4.4最大的变化就是引入ART模式来代替Dalvik虚拟机.ART是Android Runtime的缩写,它提供了以AOT(Ahead-Of-Time)的方式运行Android应用程序的 ...
最新文章
- MySQL性能优化速记
- 用VS.NET 2005重构你的代码
- 数据中心空调故障案例集(第二季)
- 【数据库复习】第一章绪论
- 【Spring注解系列13】Spring自动装配总结:@Autowired、@Resource、@Qualifier、@Inject
- m_Orchestrate learning system---二十、如何写代码不容易犯错
- java版b2b2c社交电商spring cloud分布式微服务:服务消费(Ribbon)
- SpringBoot使用@Cacheable实现最简单的Redis缓存
- 信息学奥赛一本通(1063:最大跨度值)
- JavaScript高级程序设计学习(二)之基本概念
- 开发者自述:我是如何从 0 到 1 走进 Kaggle 的
- 电脑dns_女生也能学会的修电脑技巧
- 【转帖】Mysql多维数据仓库指南 第一篇 第1章
- java数据结构与算法总结(二十五)--初识BitSet之API
- 申请美国密歇根州立大学需要具备哪些条件?
- 计算机老师教师节祝福语,送给老师教师节祝福语
- 如何在网页标题前添加图标
- 汽车转向前后轮轨迹matlab程序,车前进后退方向的口诀,动画图解车前后轮转弯轨迹...
- idea 项目添加图片或更换图片 引用后没反应(清缓存)
- Flash----读写外部Flash
热门文章
- 体验游戏,就在即刻!Google Play Instant
- 用谷歌浏览器播放audioSource的坑
- 心灵鸡汤若干,不喜勿入
- 测试面试题之白盒测试的实用技术(问题及答案)
- 自学的程序员一点竞争力都没有么?投简历都没有回应?
- endnote文献顺序编号不对_EndNote插入文献序号排序混乱如何解决
- 安信可的GPRS+GSM模组A9连接机智云的教程
- cs和msf配合进行内网的操作
- php下载excel文件模板文件,PHP下载excel文件变得腐败
- 简介 - Energy是Go基于Chromium构建Windows、Linux、MacOSX的跨平台桌面应用框架