Android开发教程:SurfaceView使用实例
Android开发教程:SurfaceView使用实例
同样,先上效果图如下:
效果图中,抛物线的动画即是由SurfaceView实现的。底部栏中的文字翻转详情相关帖子:
Android开发教程:文字翻转动画的实现
需求:
1.实现抛物线动画
1.1 设计物理模型,能够根据时间变量计算出某个时刻图片的X/Y坐标。
1.2 将图片高频率(相比于UI线程的缓慢而言)刷新到界面中。这儿需要实现将脏界面清屏及刷新操作。
2.文字翻转动画(已解决,见上面的帖子链接)
下面来逐一解决所提出的问题。
-----------------------------------------------------------------------------
分隔线内容与Android无关,请慎读,勿拍砖。谢啦
1.1 设计物理模型,如果大家还记得初中物理时,这并不难。自己写的草稿图见下:
可以有:图片要从高度为H的位置下落,并且第一次与X轴碰撞时会出现能量损失,至原来的N%。并且我们需要图片的最终落点离起始位置在X轴上的位移为L,默认存在重力加速度g。
详细的物理分析见上图啦,下面只说代码中如何实现,相关代码在PhysicalTool.java。
第一次下落过程所耗时t1与高度height会有如下关系:
- t1 = Math.sqrt(2 * height * 1.0d / GRAVITY);
- t2 = Math.sqrt((1 - WASTAGE) * 2 * height * 1.0d / GRAVITY);
- velocity = width * 1.0d / (t1 + 2 * t2);
PhysicalTool.comput()
- double used = (System.currentTimeMillis() - startTime) * 1.0d / 1000;
- x = velocity * used;
- if (0 <= used && used < t1) {
- y = height - 0.5d * GRAVITY * used * used;
- } else if (t1 <= used && used < (t1 + t2)) {
- double tmp = t1 + t2 - used;
- y = (1 - WASTAGE) * height - 0.5d * GRAVITY * tmp * tmp;
- } else if ((t1 + t2) <= used && used < (t1 + 2 * t2)) {
- double tmp = used - t1 - t2;
- y = (1 - WASTAGE) * height - 0.5d * GRAVITY * tmp * tmp;
- }
----------------------------------------------------------------------------------------
1.2 SurfaceView刷新界面
SurfaceView是一个特殊的UI组件,特殊在于它能够使用非UI线程刷新界面。至于为何具有此特殊性,将在另一个帖子"SurfaceView 相关知识笔记"中讨论,该帖子将讲述SurfaceView、Surface、ViewRoot、Window Manager/Window、Canvas等之间的关系。
使用SurfaceView需要自定义组件继承该类,并实现SurfaceHolder.Callback,该回调提供了三个方法:
- surfaceCreated()//通知Surface已被创建,可以在此处启动动画线程
- surfaceChanged()//通知Surface已改变
- surfaceDestroyed()//通知Surface已被销毁,可以在此处终止动画线程
- //于SurfaceView类中,该类实现SurfaceHolder.Callback接口,如本例中的ParabolaView
- SurfaceHolder holder = getHolder();
- holder.addCallback(this);
刷新界面首先需要执行holder.lockCanvas()锁定Canvas并获得Canvas实例,然后进行界面更新操作,最后结束锁定Canvas,提交界面更改,至Surface最终显示在屏幕上。
代码如下:
- canvas = holder.lockCanvas();
- … … … …
- … … … …
- canvas.drawBitmap(bitmap, x, y, paint);
- holder.unlockCanvasAndPost(canvas);
本例中,需要清除屏幕脏区域,出于简便的做法,是将整个SurfaceView背景重复地设置为透明,代码为:
- canvas.drawColor(Color.TRANSPARENT, android.graphics.PorterDuff.Mode.CLEAR);
Android开发之SurfaceView
惯例,Java代码如下,XML请自行实现
- ActSurfaceView.java
- package lab.sodino.surfaceview;
- import lab.sodino.surfaceview.RotateAnimation.InterpolatedTimeListener;
- import android.app.Activity;
- import android.graphics.BitmapFactory;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Handler.Callback;
- import android.os.Message;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.Button;
- import android.widget.TextView;
- public class ActSurfaceView extends Activity implements OnClickListener, ParabolaView.ParabolaListener, Callback,
- InterpolatedTimeListener {
- public static final int REFRESH_TEXTVIEW = 1;
- private Button btnStartAnimation;
- /** 动画界面。 */
- private ParabolaView parabolaView;
- /** 购物车处显示购物数量的TextView。 */
- private TextView txtNumber;
- /** 购物车中的数量。 */
- private int number;
- private Handler handler;
- /** TextNumber是否允许显示最新的数字。 */
- private boolean enableRefresh;
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- handler = new Handler(this);
- number = 0;
- btnStartAnimation = (Button) findViewById(R.id.btnStartAnim);
- btnStartAnimation.setOnClickListener(this);
- parabolaView = (ParabolaView) findViewById(R.id.surfaceView);
- parabolaView.setParabolaListener(this);
- txtNumber = (TextView) findViewById(R.id.txtNumber);
- }
- public void onClick(View v) {
- if (v == btnStartAnimation) {
- LogOut.out(this, "isShowMovie:" + parabolaView.isShowMovie());
- if (parabolaView.isShowMovie() == false) {
- number++;
- enableRefresh = true;
- parabolaView.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.icon));
- // 设置起始Y轴高度和终止X轴位移
- parabolaView.setParams(200, ((ViewGroup) txtNumber.getParent()).getLeft());
- parabolaView.showMovie();
- }
- }
- }
- public void onParabolaStart(ParabolaView view) {
- }
- public void onParabolaEnd(ParabolaView view) {
- handler.sendEmptyMessage(REFRESH_TEXTVIEW);
- }
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case REFRESH_TEXTVIEW:
- if (txtNumber.getVisibility() != View.VISIBLE) {
- txtNumber.setVisibility(View.VISIBLE);
- }
- RotateAnimation anim = new RotateAnimation(txtNumber.getWidth() >> 1, txtNumber.getHeight() >> 1,
- RotateAnimation.ROTATE_INCREASE);
- anim.setInterpolatedTimeListener(this);
- txtNumber.startAnimation(anim);
- break;
- }
- return false;
- }
- @Override
- public void interpolatedTime(float interpolatedTime) {
- // 监听到翻转进度过半时,更新txtNumber显示内容。
- if (enableRefresh && interpolatedTime > 0.5f) {
- txtNumber.setText(Integer.toString(number));
- // Log.d("ANDROID_LAB", "setNumber:" + number);
- enableRefresh = false;
- }
- }
- }
- DrawThread.java
- package lab.sodino.surfaceview;
- import android.view.SurfaceView;
- /**
- * @author Sodino E-mail:sodinoopen@hotmail.com
- * @version Time:2012-6-18 上午03:14:31
- */
- public class DrawThread extends Thread {
- private SurfaceView surfaceView;
- private boolean running;
- public DrawThread(SurfaceView surfaceView) {
- this.surfaceView = surfaceView;
- }
- public void run() {
- if (surfaceView == null) {
- return;
- }
- if (surfaceView instanceof ParabolaView) {
- ((ParabolaView) surfaceView).handleThread();
- }
- }
- public void setRunning(boolean b) {
- running = b;
- }
- public boolean isRunning() {
- return running;
- }
- }
|
评论暂时关闭