Android 动画初探
前言:
好久没来写文章了,一方面是因为自己懒了,另外一个是因为最近工作比较忙,没有闲时间(其实主要还是因为懒)。话说八月多换了一个新工作,在之前的公司,主要是横向发展,了解了很多技术。在现在的公司主要是纵向发展,更加深入的探索。之前是广而不精,没有深入学习。在现在的公司呢,能够更加深入的学习技术。就拿最近的工作来说吧,动画很多,刚开始只是知道Android动画分为属性动画、帧动画和补间动画。但是,他们之间有什么具体的区别就不是特别清楚了。尤其是属性动画和补间动画的区别,我能说自己被补间动画坑惨了吗?(其实,还是自己学艺不精,需要继续努力了。)好了,废话说多了,还是来看看今天的文章吧。
首先
要学习Android动画,我们以一个例子来深入学习,毕竟都是要把功能实现出来,写一些大而空没有实用性的东西,不但是敷衍别人,更是对自己的不负责任。如下图所示:(原谅我自恋一下,放了自己的图像照)
- 分析
1、要实现从大图到小图的过度,我们需要怎么实现呢?又需要用哪些技术呢?首先图片缩小了,那么就需要缩放动画;其次,图片向右移动和向上移动了,那么就需要位移动画。背景动画是用Lottie实现的,中间的圆形变叉也是用的lottie监听帧率变化,这个不在今天的讨论和实现范围内。今天主要实现布局从大到小的缩放和移动。
2、 那么缩放和移动可以用哪些动画实现呢?可能有朋友说是用补间动画实现了,那么如果布局上面有点击事件呢?点击事件的位置在原位置还是新位置呢?答案是还在原来的位置,补间动画只能实现view的变化,而不能改变点击事件的位置,如果只是做一个页面展示用,那么补间动画完全够用了。但是,如果想改变点击事件的位置,必须要用属性动画。我能说我在这里被坑了好久吗?好了,现在来看看我们如何实现控件的缩放和移动。
其次
/** * 动画 */ public static void scanAnimation(Context context, FrameLayout mLytAll) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); final int width = dm.widthPixels;// 屏幕宽度(像素) int height = dm.heightPixels;// 屏幕高度(像素) ObjectAnimator translationX = ObjectAnimator.ofFloat(mLytAll, "translationX", 1, (DensityUtils.px2dp(context, width) - 36)); ObjectAnimator translationY = ObjectAnimator.ofFloat(mLytAll, "translationY", 1, -(DensityUtils.px2dp(context, height) - 23)); ObjectAnimator scaleX = ObjectAnimator.ofFloat(mLytAll, "scaleX", (94 / DensityUtils.px2dp(context, width))); ObjectAnimator scaleY = ObjectAnimator.ofFloat(mLytAll, "scaleY", (166 / DensityUtils.px2dp(context, height))); AnimatorSet animatorSet = new AnimatorSet(); //组合动画 animatorSet.playTogether(translationX, translationY, scaleX, scaleY); //设置动画 animatorSet.setDuration(350); animatorSet.start(); }
- 分析:
1、这里要移动,那么就需要屏幕的宽和高,然后进行等比缩放,因为上面和右边有一定的距离,那么就要计算右边距和上边距;
2、这里因为是X轴和Y轴进行移动并且缩放,所以我这边用了组合动画,AnimatorSet;
3、X轴的移动动画用了ObjectAnimator然后设置X轴移动和Y轴移动,。假设,距离右边距是36dp,上边距是23。那么X轴的移动就是,从1到屏幕宽转换成dp值后减去右边距(36dp)。Y轴的移动就是屏幕的高转换为dp后减去上边距(23dp),然后加上一个负号(-),为什么呢,因为Y轴向上为负,向下为正;
4、现在来看缩放动画,假设缩放后的小屏幕高是166dp,宽是94dp,那么就是缩放后的屏幕宽(94dp)除以屏幕宽转换成dp值之后的比率了。当然,这样做显然是不太严谨的(为什么说不严谨呢,后面会讲)。Y轴的缩放呢就是缩放后小图的高(166dp)除以屏幕高转换成dp之后的值。
5、完成后用AnimatorSet设置X轴Y轴的平移和缩放动画同步进行,然后设置动画的执行时长至此就完成了动画从大屏幕到小屏幕的移动和缩放。
再次
之前在分析的时候说上面直接写死宽高值之后进行缩放不严谨,那么我们来分析一下。因为Android手机屏幕分辨率很多,如果在大屏幕手机上面可能不会出现太大的问题,那么在屏幕分辨率比较低的手机上呢?有可能显示不全或者按钮挤压到一起去了。那么,就要动态计算小屏幕的宽高了。比如说UI给了我们的UI图的宽高比是360640,那么我们如何来动态计算屏幕的宽高比呢?那么,X轴的缩放比率就不应该是94/DensityUtils.px2dp(context, width))了,而应该是(94(DensityUtils.px2dp(context, width))/360))/DensityUtils.px2dp(context, width)),就是说我们应该计算UI图的宽和手机实际的宽的比率乘以94再除以屏幕的宽,这才是我们需要缩放的宽。那么高呢?当然是一样的了166 / DensityUtils.px2dp(context, height)),这样写当然也是有问题的了,而应该是(166*(DensityUtils.px2dp(context, height))/640))/DensityUtils.px2dp(context, height)),这样才是更加严谨的写法。
/** * 动画 */ public static void scanAnimation(Context context, FrameLayout mLytAll) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); final int width = dm.widthPixels;// 屏幕宽度(像素) int height = dm.heightPixels;// 屏幕高度(像素) ObjectAnimator translationX = ObjectAnimator.ofFloat(mLytAll, "translationX", 1, (DensityUtils.px2dp(context, width) - 36)); ObjectAnimator translationY = ObjectAnimator.ofFloat(mLytAll, "translationY", 1, -(DensityUtils.px2dp(context, height) - 23)); ObjectAnimator scaleX = ObjectAnimator.ofFloat(mLytAll, "scaleX", ((94(DensityUtils.px2dp(context, width)/360)) / DensityUtils.px2dp(context, width))); ObjectAnimator scaleY = ObjectAnimator.ofFloat(mLytAll, "scaleY", ((166(DensityUtils.px2dp(context, height)/640)) / DensityUtils.px2dp(context, height))); AnimatorSet animatorSet = new AnimatorSet(); //组合动画 animatorSet.playTogether(translationX, translationY, scaleX, scaleY); //设置动画 animatorSet.setDuration(350); animatorSet.start(); }
最后
好了,今天就写到这里,如果有不正确的还希望各位指正,小可这里不胜感激,还有就是,能用属性动画实现的,尽量不要用补间动画来做,因为你会碰到各种坑。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
js判断是否安装某个android app,没有安装下载该应用(websocket通信,监听窗口失去焦点事件)
现在经常有写场景需要提示用户下载app, 但是如果用户已经安装,我们希望是直接打开app。 实际上,js是没有判断app是否已经安装的方法的,我们只能曲线救国。 首先,我们需要有call起app的schema, 以及一个下载地址,比如: var schema = 'myApp://main'; var downUrl = 'https://yourmain.com/downloadUrlTag'; 一、使用websocket通信实现页端和app的通信 1. android app需要实现websocket的连接功能,开放一个特定的端口如8899; 2. 页端js建立websocket连接 1 var download = function (schema, downUrl) { 2 var ws = "ws://localhost:8899/websocket"; 3 4 function onMessage(event) { 5 if (event.data != 'SUCCESS') { 6 console.log(event.data + "!= 'SUCCESS'"); 7 ...
- 下一篇
PopupWindow 使用详解(一) 中文API 文档 赠送 ListPopupWindow 中文 API
笔者数了数枕巾脱落的头发,发现了 Android 开发常用的类似于弹窗的悬浮窗口 大概是 PopupWindow 和 dialog。之前有还算具体的写过关于 dialog 以及自定义 dialog 甚至是 dialogActivity 的相关笔记,即:Android 系统原生dialog使用 、Android dialog Activity 使用 、android自定义相对复杂dialog 。突然感觉 PopupWindow 这个说简单不简单,说难不难的知识点也应该详细研究一下。下面回归正题,请欣赏笔者的表演: 一、创建 PopupWindow 先说一下 Google 爸爸提供的构造方法 public PopupWindow() public PopupWindow(View contentView) public PopupWindow(int width, int height) public PopupWindow(View contentView, int width, int height) public PopupWindow(View contentView, int w...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS关闭SELinux安全模块