深入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动画系统框架简介.今天接着来 ...
随机推荐
- iOS下拉刷新和上拉刷新
在iOS开发中,我们经常要用到下拉刷新和上拉刷新来加载新的数据,当前这也适合分页.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 上拉刷新 1.在TableView里,一打开软件, ...
- .net 调用API并解析Json数据方法
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using Syst ...
- linq to sql 左联接出错,未将对象引用设置到实例
var result = from a in model join b in orderDetailModel on a.FoodMenuID equals b.FoodMenuID into g f ...
- Javascript-闰年javascript的判断
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 021-centos6.5上二进制安装mysql5.7.22
思路: 下载上传mysql的二进制安装包. 准备好mysql的用户.安装目录basedir.数据目录datadir.配置文件/etc/my.cnf. 初始化出数据库. 配置启动服务. 开机启动. 配置 ...
- HDFS文件操作
hadoop装好后,文件系统中没有任何目录与文件 1. 创建文件夹 hadoop fs -mkdir -p /hkx/learn 参数-p表示递归创建文件夹 2. 浏览文件 hadoop fs -ls ...
- Ignite内存数据库与sql支持
Ignite采用h2作为内存数据库,支持h2的一切sql语法.如果是本地缓存或者复制缓存,sql执行直接在本地h2数据库中执行,如果是分区缓存,ignite则会分解sql到多个h2数据库执行后再汇总. ...
- 很全的linux网络编程技巧
本文转载自:http://www.cnblogs.com/jfyl1573/p/6476607.html 1. LINUX网络编程基础知识 1 1.1. TCP/IP协议概述 1 1.2. OSI参考 ...
- git仓库按时间、成员等维度分析统计
git 按时间打印所有成员代码提交: git log --since ==2018-01-01 --until=2018-12-31 --format='%aN' | sort -u | while ...
- MySQL数据库----触发器
触发器-trigger 触发器:监视某种情况,并触发某种操作. 使用触发器可以定制用户对表进行[增.删.改]操作时前后的行为,注意:没有查询 -- 触发器:某种程序触发了工具的运行 -- 触发器不能主 ...