从点到面,给Button的属性动画
属性动画是API 11加进来的一个新特性,其实在现在来说也没什么新的了。属性动画可以对任意view的属性做动画,实现动画的原理就是在给定的时间内把属性从一个值变为另一个值。因此可以说属性动画什么都可以干,只要view有这个属性。
所以我们这里对Button来做一个简单的属性动画:改变这个Button的宽度。也可以用Tween Animation,但是明显有一点不能满足要求的地方是Tween Animation只能做Scale动画,也就是缩放。你可以对这个button做缩放来达到增加宽度的效果,但是这个时候按钮的文字也会跟着出现缩放和变形。同时很重要的一点,Tween Animation不改变view的本来位置和大小。看起来这个按钮变大了,但是点击动画执行前的按钮没有覆盖的位置是没有效果的。
我们简略的看一下这个Tween动画是怎么样的。
首先,用xml的文件定义一个Scale动画,对宽度扩大为原来的两倍,高度扩大为原来的六倍。在动画之后填充。动画执行完成后就可以清楚的看到按钮文字跟着按钮动画执行完成后之后的效果。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<scale
android:fromXScale="100%"
android:fromYScale="100%"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="200%"
android:toYScale="600%" />
</set>
执行这个Tween动画:
var button = findViewById(R.id.tween_button) as Button
button.setOnClickListener { v ->
var anim = AnimationUtils.loadAnimation(this@TweenAnimActvity, R.anim.scale_anim)
v.startAnimation(anim)
}
这里必须说明,上面这段代码是Kotlin语言写的。自从用了之后就再不想用java了。只要你有一定的java基础,阅读这段代码并没有什么难度。
点击原来按钮区域以外的地方,按钮是不会有任何的反应的。
看看效果:

试试Property动画吧
直接看看按照同样的缩放大小生成的效果吧:

前后两者相差还是很明显的。越明显越突出了属性动画存在的必要。这种必要不止是效果上看到的,
还有交互和开发的时候代码相关的。
所以无论如何都要使用属性动画了。这里使用最简答的方法: ObjectAnimator来做这个动画:
ObjectAnimator.ofInt(mAnimateButton, "width", mAnimateButton.getWidth(), 1000)
.setDuration(1000)
.start();
看起来很简单就实现了按钮的动画。但是运行的时候就会出现问题。因为,属性动画在执行的时候需要改变指定的属性,这里是width,的值。使用的就是属性对应的getWidth和setWidth方法。getWidth在没有给定动画的初值时,使用这个方法获得初始值。setWidth则在给定的时间内不断地被用来修改属性值来达到动画的效果。注意,这个方法不是只是用一次。
但是来看看Button的getWidth和setWidth两个方法的代码:
/**
* Return the width of the your view.
*
* @return The width of your view, in pixels.
*/
@ViewDebug.ExportedProperty(category = "layout")
public final int getWidth() {
return mRight - mLeft;
}
/**
* Makes the TextView exactly this many pixels wide.
* You could do the same thing by specifying this number in the
* LayoutParams.
*
* @see #setMaxWidth(int)
* @see #setMinWidth(int)
* @see #getMinWidth()
* @see #getMaxWidth()
*
* @attr ref android.R.styleable#TextView_width
*/
@android.view.RemotableViewMethod
public void setWidth(int pixels) {
mMaxWidth = mMinWidth = pixels;
mMaxWidthMode = mMinWidthMode = PIXELS;
requestLayout();
invalidate();
}
显然在setWidth的时候,并没有用给定的值去修改按钮layout param的宽度。
在这种情况下Google给了三种解决方法:
- 给你的view加上get和set方法。但是这需要你有这个权限。
- 用一个类来包装目标view,间接的给这个view来添加get和set方法。
- 用
ValueAnimator和AnimatorUpdateListener监听动画,自己修改每个时间片的属性修改。
给Button添加get和set方法不是很现实,所以只能选择后两者。
下面一一介绍后面两个方法。
间接给出get、set方法
这个方法看起来很简单,定义一个类间接给出get、set方法就是这样的:
class ViewWrapper {
View mTargetView;
public ViewWrapper(View v) {
mTargetView = v;
}
public void setWidth(int width) {
mTargetView.getLayoutParams().width = width;
mTargetView.requestLayout();
}
// for view's width
public int getWidth() {
int width = mTargetView.getLayoutParams().width;
return width;
}
// for view's height
public void setHeight(int height) {
mTargetView.getLayoutParams().height = height;
mTargetView.requestLayout();
}
public int getHeight() {
int height = mTargetView.getLayoutParams().height;
return height;
}
}
- 既然动画是需要修改layout params的宽度,那么我们在这个set方法里就修改layout params的宽度。
- 返回layout params的宽度。这个值是view在动画之前的宽度。
然后在按钮点击之后开始这个修改宽度的动画:
@Override
public void onClick(View v) {
Log.d("##ViewWrapperActivity", "width is " + v.getWidth());
// 1
ViewWrapper viewWrapper = new ViewWrapper(v);
// 2
ObjectAnimator animator = ObjectAnimator.ofInt(viewWrapper, "width", /*viewWrapper.getWidth(),*/ 1500);
// 3
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.d("##ANIM", "started");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.d("##ANIM", "stopped");
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
// 4
animator.setDuration(3000).start();
}
- 用包装类包装view,这里是按钮。
- 开始动画,动画的对象现在为包装类对象。这里可以修改属性动画的定义了,属性动画可以对任何对象修改属性。这里的包装类对象明显不是一个view。
- 这里增加了一个监听器,监听动画是刚开始还是已经结束。
- 开始动画。在三秒钟的时间内修改按钮的宽度,从初始值修改为1500像素宽。
看起来已经很完美了,运行这个段代码。点击按钮后。好吧,这个动画很奇怪,并没有运行“完全”。点一下动一点,但是没有达到宽度为1500像素。虽然动画监听器AnimatorListener的方法onAnimationEnd已经执行,而且也打出了执行完成的log,但是宽度始终达不到。所以说动画执行并不“完全”。
那么这是为什么呢?先给出正确的代码各位可以参考着考虑一下:
public class ViewWrapperActivity extends Activity implements View.OnClickListener {
private Button mAnimateButton;
// 1
private ViewWrapper mWrapper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_wrapper);
mAnimateButton = (Button) findViewById(R.id.animate_button);
mAnimateButton.setOnClickListener(this);
// 2
mWrapper = new ViewWrapper(mAnimateButton);
}
@Override
public void onClick(View v) {
Log.d("##ViewWrapperActivity", "width is " + v.getWidth());
// 3
int width = v.getLayoutParams().width;
int height = v.getHeight(); // current height
// 4
PropertyValuesHolder widthHolder = PropertyValuesHolder.ofInt("width", width * 2);
PropertyValuesHolder heightHolder = PropertyValuesHolder.ofInt("height", height * 6);
// 5
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mWrapper, widthHolder, heightHolder);
animator.setInterpolator(new LinearInterpolator());
animator.addListener(new Animator.AnimatorListener() {
// ...
});
animator.setDuration(3000).start();
}
}
- 声明包装类对象类成员。
- 在
onCreate方法里初始化包装类对象。 width和height获取Button当前的宽度和高度。- 在这定义对宽度做2倍的扩大,对高度做6倍的扩大。两个动画的定义都存放在
PropertyValuesHolder中,并在后面的实现中使用。使用这个类存放对不同属性的动画定义,方便使用。这两个动画会同时并行执行。 - 对
mWrapper执行前面定义的两个动画。这两个动画同时执行。要使两个动画顺序执行可以AnimatorSet来实现:
int width = v.getWidth();
int height = v.getHeight();
AnimatorSet animSet = new AnimatorSet();
ObjectAnimator widthAnim = ObjectAnimator.ofInt(mSequenceWrapper, "width", width * 2);
ObjectAnimator heightAnim = ObjectAnimator.ofInt(mSequenceWrapper, "height", height * 6);
animSet.play(widthAnim).before(heightAnim);
animSet.setDuration(1000);
animSet.setInterpolator(new AccelerateDecelerateInterpolator());
animSet.start();
这样就可以一次动画达到指定宽度和高度了。具体是为什么呢?欢迎再后面的评论中一起讨论。
从点到面,给Button的属性动画的更多相关文章
- 属性动画 LayoutTransition AnimatorInflater Keyframe 新特性
LayoutTransition设置动画 使用LayoutTransition可为布局的容器设置动画,当容器中的视图层次发生变化时产生相应的过渡的动画效果 过渡的类型一共有四种: LayoutTran ...
- Android属性动画
这几天看郭神的博客 Android属性动画完全解析(上),初识属性动画的基本用法之后,我自己突然想实现一种动画功能,就是我们在携程网.阿里旅行等等手机APP端买火车票的时候,看到有选择城市,那么就有出 ...
- android 帧动画,补间动画,属性动画的简单总结
帧动画——FrameAnimation 将一系列图片有序播放,形成动画的效果.其本质是一个Drawable,是一系列图片的集合,本身可以当做一个图片一样使用 在Drawable文件夹下,创建ani ...
- View动画和属性动画
在应用中, 动画效果提升用户体验, 主要分为View动画和属性动画. View动画变换场景图片效果, 效果包括平移(translate), 缩放(scale), 旋转(rotate), 透明(alph ...
- 使用属性动画 — Property Animation
属性动画,就是通过控制对象中的属性值产生的动画.属性动画是目前最高级的2D动画系统. 在API Level 11中添加.Property Animation号称能控制一切对象的动画,包括可见的和不可见 ...
- 【转】android 属性动画之 ObjectAnimator
原文网址:http://blog.csdn.net/feiduclear_up/article/details/39255083 前面一篇博客讲解了 android 简单动画之 animtion,这里 ...
- Android属性动画之ValueAnimation
ValueAnimation是ObjectAnimation类的父类,经过前几天的介绍,相信大家对ObjectAnimation有了 一定的认识,今天就为大家最后介绍一下ValueAnimation, ...
- Android属性动画之ObjectAnimator
相信对于Android初学者,对于Android中的动画效果一定很感兴趣,今天为大家总结一下刚刚学到的属性动画案例. 首先和一般的Android应用一样,我们先建一个工程,为了方便,我们的布局文件中就 ...
- Android Animation学习(四) ApiDemos解析:多属性动画
Android Animation学习(四) ApiDemos解析:多属性动画 如果想同时改变多个属性,根据前面所学的,比较显而易见的一种思路是构造多个对象Animator , ( Animator可 ...
随机推荐
- golang 创建一个简单的连接池,减少频繁的创建与关闭
一.连接池的描述图片如下: 二.连接池代码如下: package main; import ( "time" "sync" "errors" ...
- Vmware黑屏解决方法
此原因是显卡性能差,显示选项开启了3D加速导致的,具体修改步骤: 英文路径:VM->Settings->Hardware->Display 在右面的内容栏中将 Accelerate ...
- ----转载----【前端工具】Chrome 扩展程序的开发与发布 -- 手把手教你开发扩展程序
关于 chrome 扩展的文章,很久之前也写过一篇.清除页面广告?身为前端,自己做一款简易的chrome扩展吧. 本篇文章重在分享一些制作扩展的过程中比较重要的知识及难点. 什么是 chrome 扩展 ...
- Informatica_(6)性能调优
六.实战汇总31.powercenter 字符集 了解源或者目标数据库的字符集,并在Powercenter服务器上设置相关的环境变量或者完成相关的设置,不同的数据库有不同的设置方法: 多数字符集的问题 ...
- 安卓项目R,java文件不能自动更新,clean之后,R.java消失 (转自 Cynosure鱼)
今天整了个安卓项目,新增加了个跳转页面,添加完背景图,发现有个R.id找不到了,于是clean了一下,这下出问题了,发现各处的R.id都找不到,报错.结果一看是R.java没了然后各种百度结果:有 ...
- 应用内直接跳转到Appstore
iOS开发中,应用内直接跳转到Appstore .进入appstore中指定的应用 NSString *str = [NSString stringWithFormat: @"itms:// ...
- React中使用CSS
第一种: 在组件中直接使用style 不需要组件从外部引入css文件,直接在组件中书写. import React, { Component } from "react"; con ...
- 堆和索引堆的实现(python)
''' 索引堆 ''' ''' 实现使用2个辅助数组来做.有点像dat.用哈希表来做修改不行,只是能找到这个索引,而需要change操作 还是需要自己手动写.所以只能用双数组实现. #引入索引堆的核心 ...
- centos下安装配置jetty
下载jdk-8u144-linux-x64.tar.gz # tar -zxvf jdk-8u144-linux-x64.tar.gz # mv jdk1.8.0_144 /usr/java/ # u ...
- jsvascript null,undefined,undeclared的区别
1.undefined表示"缺少值",就是此处应该有一个值,但是还没有定义,转为数值时为NaN.典型用法是: (1)变量被声明了,但没有赋值时,就等于undefined. (2) ...