深入Animation,在SurfaceView中照样使用Android—Tween Animation!
即通过对对象不断做图像变换(平移、缩放、旋转)产生动画效果!实现方式其实就是预先定义一组指令,这些指令指定了图形变换的类型、触发时间、持续时
间。这些指令可以是以 XML 文件方式定义,也可以是以源代码方式定义。程序沿着时间线执行这些指令就可以实现动画 效果。
游戏开发中我们优先选用两种方式:第一种设置可视区域的方式来实现动画效果(帧动画),需要童鞋们手动实现,那么在之前我的博文【Android2D游戏
开发之四】中已经有了相应的源码!大家可以去下载研究;那么这里就主要为大家详细分析 Tween Animation!
- package com.himi.frameAnimation;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.animation.AlphaAnimation;
- import android.view.animation.Animation;
- import android.view.animation.RotateAnimation;
- import android.view.animation.ScaleAnimation;
- import android.view.animation.TranslateAnimation;
- /**
- *@author Himi
- *@AlphaAnimation 渐变透明度动画效果
- *@ScaleAnimation 渐变尺寸伸缩动画效果
- *@TranslateAnimation 画面转换位置移动动画效果
- *@RotateAnimation 画面转移旋转动画效果
- */
- public class MyViewAnimation extends View {
- private Paint paint;
- private Bitmap bmp;
- private int x = 50;
- private Animation mAlphaAnimation;
- private Animation mScaleAnimation;
- private Animation mTranslateAnimation;
- private Animation mRotateAnimation;
- public MyViewAnimation(Context context) {
- super(context);
- paint = new Paint();
- paint.setAntiAlias(true);
- bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
- this.setFocusable(true);//只有当该View获得焦点时才会调用onKeyDown方法
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.BLACK);
- paint.setColor(Color.WHITE);
- canvas.drawText("Himi", x, 50, paint);//备注1
- canvas.drawText("方向键↑ 渐变透明度动画效果", 80, this.getHeight() - 80, paint);
- canvas.drawText("方向键↓ 渐变尺寸伸缩动画效果", 80, this.getHeight() - 60, paint);
- canvas.drawText("方向键← 画面转换位置移动动画效果", 80, this.getHeight() - 40, paint);
- canvas.drawText("方向键→ 画面转移旋转动画效果", 80, this.getHeight() - 20, paint);
- canvas.drawBitmap(bmp, this.getWidth() / 2 - bmp.getWidth() / 2,
- this.getHeight() / 2 - bmp.getHeight() / 2, paint);
- x += 1;
- }
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {//渐变透明度动画效果
- mAlphaAnimation = new AlphaAnimation(0.1f, 1.0f);
- //第一个参数fromAlpha 为动画开始时候透明度
- //第二个参数toAlpha 为动画结束时候透明度
- //注意:取值范围[0-1];[完全透明-完全不透明]
- mAlphaAnimation.setDuration(3000);
- ////设置时间持续时间为3000 毫秒=3秒
- this.startAnimation(mAlphaAnimation);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {//渐变尺寸伸缩动画效果
- mScaleAnimation = new ScaleAnimation(0.0f, 1.5f, 0.0f, 1.5f, Animation
- .RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.0f);
- //第一个参数fromX为动画起始时X坐标上的伸缩尺寸
- //第二个参数toX为动画结束时X坐标上的伸缩尺寸
- //第三个参数fromY为动画起始时Y坐标上的伸缩尺寸
- //第四个参数toY 为动画结束时Y 坐标上的伸缩尺寸
- //注意:
- //0.0表示收缩到没有
- //1.0表示正常无伸缩
- //值小于1.0表示收缩
- //值大于1.0表示放大
- //-----我这里1-4参数表明是起始图像大小不变,动画终止的时候图像被放大1.5倍
- //第五个参数pivotXType 为动画在X 轴相对于物件位置类型
- //第六个参数pivotXValue 为动画相对于物件的X 坐标的开始位置
- //第七个参数pivotXType 为动画在Y 轴相对于物件位置类型
- //第八个参数pivotYValue 为动画相对于物件的Y 坐标的开始位置
- //提示:位置类型有三种,每种效果大家自己尝试哈~这里偷下懒~
- //毕竟亲眼看到效果的区别才记忆深刻~
- //Animation.ABSOLUTE 、Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT
- mScaleAnimation.setDuration(2000);
- this.startAnimation(mScaleAnimation);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {//画面转换位置移动动画效果
- mTranslateAnimation = new TranslateAnimation(0, 100, 0, 100);
- //第一个参数fromXDelta为动画起始时X坐标上的移动位置
- //第二个参数toXDelta为动画结束时X坐标上的移动位置
- //第三个参数fromYDelta为动画起始时Y坐标上的移动位置
- //第四个参数toYDelta 为动画结束时Y 坐标上的移动位置
- mTranslateAnimation.setDuration(2000);
- this.startAnimation(mTranslateAnimation);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {//画面转移旋转动画效果
- mRotateAnimation = new RotateAnimation(0.0f, 360.0f,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
- //第一个参数fromDegrees为动画起始时的旋转角度
- //第二个参数toDegrees 为动画旋转到的角度
- //第三个参数pivotXType 为动画在X 轴相对于物件位置类型
- //第四个参数pivotXValue 为动画相对于物件的X 坐标的开始位置
- //第五个参数pivotXType 为动画在Y 轴相对于物件位置类型
- //第六个参数pivotYValue 为动画相对于物件的Y 坐标的开始位置
- mRotateAnimation.setDuration(3000);
- this.startAnimation(mRotateAnimation);
- }
- return super.onKeyDown(keyCode, event);
- }
- }
相对位置是屏幕左上角,绝对位置! //Animation.RELATIVE_TO_SELF
相对位置是自身View;取值为0,是自身左上角,取值为1是自身的右下角; //Animation.RELATIVE_TO_PARENT
相对父类View的位置
Animation下的每种动画效果的实例化的每个参数都解释的很详细了!其实动画的实现不光用代码可以实现,在xml中注册实现也是可以的,这里就不多
写了,大家可以自己去尝试写一下,那么在view中我们播放一种特效动画,只要实例化其对象,然后设置下参数,然后startAnimation()就好
了,步骤很简单,只是每个动画实例化的参数确有着千变万化的改法,这些我也没法子一一来给大家演示,大家可以自己改改参数看看实际的效果!当然对于每种动
画我们不光有设置播放的时候,还有一些属性和方法可以调用,比如Animation.restart()重放动
画,getTransformation()此方法返回假,说明动画完成等等很多属性,请各位童鞋自定实验 o(∩_∩)o 哈哈~
Canvas.drawBitmap (bmp, x, y, Paint) 绘制时,android 会先把 bmp
做一次矩阵运算,然后将运算的结果显示在 Canvas 上,然后不断修改 Canvas 的矩阵并刷新屏幕,View
里的对象就会不停的做图形变换,动画就形成了。
MySurfaceViewAnimation.java
- package com.himi.frameAnimation;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.SurfaceHolder.Callback;
- import android.view.animation.AlphaAnimation;
- import android.view.animation.Animation;
- import android.view.animation.RotateAnimation;
- import android.view.animation.ScaleAnimation;
- import android.view.animation.TranslateAnimation;
- /**
- *@author Himi
- */
- public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable {
- private Thread th = new Thread(this);
- private SurfaceHolder sfh;
- private Canvas canvas;
- private Paint paint;
- private Bitmap bmp;
- ///
- private Animation mAlphaAnimation;
- private Animation mScaleAnimation;
- private Animation mTranslateAnimation;
- private Animation mRotateAnimation;
- public MySurfaceViewAnimation(Context context) {
- super(context);
- Log.v("Himi", "MySurfaceView");
- this.setKeepScreenOn(true);
- bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
- sfh = this.getHolder();
- sfh.addCallback(this);
- paint = new Paint();
- paint.setAntiAlias(true);
- setFocusable(true);
- setFocusableInTouchMode(true);
- // this.setBackgroundResource(R.drawable.icon);//备注2
- }
- public void surfaceCreated(SurfaceHolder holder) {
- Log.v("Himi", "surfaceCreated");
- th.start();
- }
- public void draw() {
- try {
- canvas = sfh.lockCanvas();
- if (canvas != null) {
- canvas.drawColor(Color.BLACK);
- paint.setColor(Color.WHITE);
- canvas.drawText("方向键↑ 渐变透明度动画效果", 80, this.getHeight() - 80, paint);
- canvas.drawText("方向键↓ 渐变尺寸伸缩动画效果", 80, this.getHeight() - 60, paint);
- canvas.drawText("方向键← 画面转换位置移动动画效果", 80, this.getHeight() - 40, paint);
- canvas.drawText("方向键→ 画面转移旋转动画效果", 80, this.getHeight() - 20, paint);
- canvas.drawBitmap(bmp, this.getWidth() / 2 - bmp.getWidth() / 2,
- this.getHeight() / 2 - bmp.getHeight() / 2, paint);
- }
- } catch (Exception e) {
- Log.v("Himi", "draw is Error!");
- } finally {
- sfh.unlockCanvasAndPost(canvas);
- }
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {//渐变透明度动画效果
- mAlphaAnimation = new AlphaAnimation(0.1f, 1.0f);
- mAlphaAnimation.setDuration(3000);
- this.startAnimation(mAlphaAnimation);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {//渐变尺寸伸缩动画效果
- mScaleAnimation = new ScaleAnimation(0.0f, 2.0f,
- 1.5f, 1.5f, Animation.RELATIVE_TO_PARENT,
- 0.5f, Animation.RELATIVE_TO_PARENT, 0.0f);
- mScaleAnimation.setDuration(2000);
- this.startAnimation(mScaleAnimation);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {//画面转换位置移动动画效果
- mTranslateAnimation = new TranslateAnimation(0, 100, 0, 100);
- mTranslateAnimation.setDuration(2000);
- this.startAnimation(mTranslateAnimation);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {//画面转移旋转动画效果
- mRotateAnimation = new RotateAnimation(0.0f, 360.0f,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
- mRotateAnimation.setDuration(3000);
- this.startAnimation(mRotateAnimation);
- }
- return super.onKeyDown(keyCode, event);
- }
- public void run() {
- // TODO Auto-generated method stub
- while (true) {
- draw();
- try {
- Thread.sleep(100);
- } catch (Exception ex) {
- }
- }
- }
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.v("Himi", "surfaceChanged");
- }
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v("Himi", "surfaceDestroyed");
- }
- }
动画代码实现跟View中的做法一样,运行模拟器发现按键没效果,不是按键没触发是本来就存在问题, - -。但是!大家可以把此类里有一行,也就是(备注2)的注释打开,我们给设置背景图,然后在模拟器上的运行效果如下图:
有些文章里说“给SurfaceView添加双缓冲”,其实是在画蛇添足 -
-,而且介绍的时候拿着单线程与双线程例子来解释双缓冲更高效的实现方法;我想弱弱的问什么是双缓冲???
如果SurfaceView不具备双缓冲,那敢问上面这张截图如何解释????
其实要实现双缓冲,只需要是新建一个Bitmap和Canvas,用这个新建的Canvas把正弦波画到新建的Bitmap,画完再通过
sfh.lockCanvas获取SurfaceView对应的Canvas,用这个Canvas把新建的Bitmap画到SurfaceView上去,
这才叫双缓冲; 还有双缓存和多线程没关系!
Surfaceview的那张截图确实也正常的动画操作了,原因又何在?而且我们设置的背景图覆盖我们draw出来的字体!!效果很不理想;那么经过考虑
我决定利用布局把View和SurfaceView都一并显示,用View主要去完成动画部分,(那么关于如何一并显示,或者说同时在
SurfaceView中添加组件,在之前的【Android 2D开发之六】 和 【Android
2D开发之七】都有了详细讲解,那么在这里),当然一并显示也会有问题,比如我们存在了view和Surfaceiew,那么按键的时候触发的哪个?或者
说如何去控制这两个View?放心,我下面就跟大家一一来讲解!
main.xml中的代码
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1" >
- <com.himi.MySurfaceView android:id="@+id/view3d"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"/>
- <com.himi.MyView android:id="@+id/myview"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"/>
- </RelativeLayout>
- </LinearLayout>
- package com.himi;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.util.AttributeSet;
- import android.view.KeyEvent;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.SurfaceHolder.Callback;
- /**
- *
- * @author Himi
- *
- */
- public class MySurfaceView extends SurfaceView implements Callback, Runnable {
- public static MySurfaceView msrv ;//----备注1
- private int move_x = 2, x = 20;
- private Thread th;
- private SurfaceHolder sfh;
- private Canvas canvas;
- private Paint p;
- public MySurfaceView(Context context, AttributeSet attrs) {
- super(context, attrs);
- msrv=this;
- p = new Paint();
- p.setAntiAlias(true);
- sfh = this.getHolder();
- sfh.addCallback(this);
- th = new Thread(this);
- this.setKeepScreenOn(true);
- this.setFocusable(true);// ----备注2
- }
- public void surfaceCreated(SurfaceHolder holder) {
- th.start();
- }
- public void draw() {
- canvas = sfh.lockCanvas();
- if(canvas!=null){
- canvas.drawColor(Color.WHITE);
- canvas.drawText("我是 - Surfaceview", x + move_x, 280, p);
- sfh.unlockCanvasAndPost(canvas);
- }
- }
- private void logic() {
- x += move_x;
- if (x > 200 || x < 80) {
- move_x = -move_x;
- }
- }
- @Override
- public boolean onKeyDown(int key, KeyEvent event) { //备注2
- return super.onKeyDown(key, event);
- }
- public void run() {
- // TODO Auto-generated method stub
- while (true) {
- draw();
- logic();
- try {
- Thread.sleep(100);
- } catch (Exception ex) {
- }
- }
- }
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- }
- public void surfaceDestroyed(SurfaceHolder holder) {
- }
- }
setFocusable(true)设置焦点了,如果都设置了,那么Android 会默认响应在xml中第一个注册的view
,而不是两个都会响应。那么为什么不同时响应呢?我解释下:
- package com.himi;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.KeyEvent;
- import android.view.Window;
- import android.view.WindowManager;
- /**
- *
- * @author Himi
- *
- */
- public class MainActivity extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- this.requestWindowFeature(Window.FEATURE_NO_TITLE);
- this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- setContentView(R.layout.main);
- MySurfaceView.msrv.setFocusable(false);//备注1
- MyView.mv.setFocusable(true);//备注1
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {//备注2
- return super.onKeyDown(keyCode, event);
- }
- }
深入Animation,在SurfaceView中照样使用Android—Tween Animation!的更多相关文章
- Android Tween Animation
View Animation, 它显示在view向上Tween Animation Tween动画.本质上没有变化View对象本身.只要改变它绘制 实施方式有两种.一个xml定义,直接在代码中的定义 ...
- android tween animation合集
自己写的一些tween animation动画xml文件,可用于activity切换,图片切换动画等 http://files.cnblogs.com/zj2012zy/anim.rar
- Android基础夯实--重温动画(一)之Tween Animation
心灵鸡汤:真正成功的人生,不在于成就的大小,而在于你是否努力地去实现自我,喊出自己的声音,走出属于自己的道路. 摘要 不积跬步,无以至千里:不积小流,无以成江海.学习任何东西我们都离不开扎实的基础知识 ...
- android之Tween Animation
android Tween Animation有四种,AlphaAnimation(透明度动画).ScaleAnimation(尺寸伸缩动画).TranslateAnimation(位移动画).Rot ...
- Android 动态背景的实现以及SurfaceView中添加EditText控件
首先还是一贯作风,我们先看案例: \ 静态图看不出来效果,如果用过此软件(扎客)的同学们都知道,她的背景会动.怎么样,是不是觉得很时尚,起码比静态的要好(个人观点).其实实现起来并不复杂,这个如果让做 ...
- Android(java)学习笔记199:Android中补间动画(Tween Animation)
本文主要简单介绍补间动画使用代码实现, 关于使用xml实现补间动画,可以参看:自定义控件三部曲之动画篇(一)——alpha.scale.translate.rotate.set的xml属性及用法 1. ...
- Android(java)学习笔记142:Android中补间动画(Tween Animation)
本文主要简单介绍补间动画使用代码实现, 关于使用xml实现补间动画, 可以参看:自定义控件三部曲之动画篇(一)——alpha.scale.translate.rotate.set的xml属性及用法 1 ...
- Android动画效果之Tween Animation(补间动画)
前言: 最近公司项目下个版本迭代里面设计了很多动画效果,在以往的项目中开发中也会经常用到动画,所以在公司下个版本迭代开始之前,抽空总结一下Android动画.今天主要总结Tween Animation ...
- Android动画学习(二)——Tween Animation
前两天写过一篇Android动画学习的概述,大致的划分了下Android Animation的主要分类,没有看过的同学请移步:Android动画学习(一)——Android动画系统框架简介.今天接着来 ...
随机推荐
- php中in_array使用注意
可能会导致长耗时: http://www.jb51.net/article/41446.htm
- Perl实战(一)
在Perl中,我们可以通过uc,lc,\U,\L来修改变量的值.其中uc,\U可以将变量中的字母全部转换为大写. lc,\L可以将变量中的字母全部转换为小写. $big = "\U$var& ...
- 利用js添加class
来来来,开篇点题. 分页应用.当在当前页时,分页的数字有个框之类的. 重要代码如下 <ul class="pagination"> <li><a hr ...
- 持续集成之四:Jenkins+sonarqube
参考其他文章,编译 构建 检查工具 参考:https://blog.csdn.net/lswnew/article/details/79193529 http://www.uml.org.cn/cod ...
- JS重要的内置对象
Array对象: 属性: .length 获得数组的长度: 方法: .concat() 连接内容或者数组,组成新的数组: .join(n) 用n连接数组的每一项组成字符串,可以是空字符串: ...
- win7 安装.Net framework 4.0出现 安装不成功,错误代码0x80240037 的解决方法
1.安装说明 系统:win7 64位 安装包:dotNetFx40_Full_x86_x64.exe(.Net framework 4.0) 出现的问题:在win7 上安装dotNetFx40_Ful ...
- PHP发送HTTP请求的6种方法
方法1: 用 file_get_contents 以get方式获取内容: <?php$url = 'https://wenda.shukaiming.com/';echo file_get_co ...
- web.xml配置详解之listener
web.xml配置详解之listener 定义 <listener> <listener-class>nc.xyzq.listener.WebServicePublishLis ...
- AP聚类算法
一.算法简介 Affinity Propagation聚类算法简称AP,是一个在07年发表在Science上的聚类算法.它实际属于message-passing algorithms的一种.算法的基本 ...
- React 回忆录(二)为什么使用 React?
Hi 各位,欢迎来到 React 回忆录!