如何在SurfaceView中在设定时间后绘制位图



为了澄清,我感兴趣的是做一个简单的动画,在几秒钟后从一个位图改变到另一个位图,然后重复。例如,如果我画了一张皱眉的脸,我如何设置它在几秒钟后被删除,并用笑脸代替它?

Here's some example code

public class MySurface extends SurfaceView implements Runnable {
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = true;
Bitmap frowny;
Bitmap smiley;
public MySurface(Context context) {
    super(context);
    init(context);
}
public MySurface(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}
public MySurface(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}
private void init(Context context) {
    // do stuff that was in your original constructor...
    ourHolder = getHolder();
    ourThread = new Thread(this);
    ourThread.start();
    frowny = BitmapFactory.decodeResource(getResources(),
            R.drawable.frowny);
    smiley = BitmapFactory
            .decodeResource(getResources(), R.drawable.smiley);

}
public void pause() {
    isRunning = false;
    while (true) {
        try {
            ourThread.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        break;
    }
    ourThread = null;
}
public void resume() {
    isRunning = true;
}
@SuppressLint("WrongCall")
public void run() {
    // TODO Auto-generated method stub
    while (isRunning) {
        if (!ourHolder.getSurface().isValid()) {
            continue;
        }
        Canvas c = ourHolder.lockCanvas();
        onDraw(c);
        ourHolder.unlockCanvasAndPost(c);
    }
}
@Override
protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    super.onDraw(canvas);
    canvas.drawBitmap(frowny, (getWidth/2), (getHeight/2), null);
    //wait a period/remove frowny
    canvas.drawBitmap(smiley, (getWidth/2), (getHeight/2), null);

    postInvalidate();
  }
}

我认为Handler是可行的方法。使用子类创建RefreshHander,如下所示:

class RefreshHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        updateImage(); // change your frown to a smiley
        view.invalidate(); // trigger onDraw()
    }
    public void sleep() {
        this.removeMessages(0);
        sendMessageDelayed(obtainMessage(0), DELAY, 0)); // how long to wait in ms
    }
}

private RefreshHandler redrawHandler = new RefreshHandler();创建redrawHandler,然后用redrawHandler.sleep();启动RefreshHander。DELAY后,handleMessage()将运行。

现在在onDraw()中,不是先画皱眉,然后画笑脸,只是让它画一个最初设置为皱眉的图像(Bitmap image; image = frown;)。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawBitmap(image, (getWidth/2), (getHeight/2), null);
}

使用updateImage()将该图像更改为笑脸符号,以便当视图无效时,下一个onDraw()将绘制笑脸符号。

private void updateImage() {
    image = smiley;
}

我建议使用AsyncTask。在doInBackground方法中,设置一个计时器,然后在onPostExecute方法中,执行动画。

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
public class AsyncTaskActivity extends Activity implements OnClickListener {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  myBitmapTask myTask = new myBitmapTask();
  myTask.execute();
}
private class myBitmapTask extends AsyncTask<Void, Void, Void> {
    @Override
    protected void onPreExecute() {}
    @Override
    protected String doInBackground(Void... params) {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.interrupted();
            }
        }
        return null;
    }
    @Override
    protected void onPostExecute(Void... Params) {
        // do bitmap animation
    }
    @Override
    protected void onProgressUpdate(Void... values) {}
}
}

注意:这没有经过测试,是在我的手机上输入的。如有错别字,请谅解

我喜欢使用asyncTask方法,因为对于您的应用程序来说,它可能过于繁琐,但您可以将相同的代码用于其他处理强度更高的任务。我通常在我的活动中做这样的事情。

public void callAsynchronousClass() {
    final Handler handler = new Handler();
    Timer timer = new Timer();
    TimerTask doAsynchronousTask = new TimerTask() {
        @Override
        public void run() {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    if (processing) {
                        try {
                            AsynchronousClassICreated myAsyncTask = new
                                    AsynchronousClassICreated();
                        myAsyncTask.execute();                            
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
};
timer.schedule(doAsynchronousTask, 0, timeUntilUpdate);

这样,你仍然可以做尽可能多的处理,然后让计时器重复调用任务,你想要多少次都可以。然后你可以像这样在asyncTask中使用on post execute方法。

public class AsynchronousssClassICreated extends AsyncTask<Void, Void, theDrawingToDo>{
    @Override
    protected void doInBackground(Void... params) {
    }
    @Override
    protected void onPostExecute(SomeClassToReturn theDrawingToDo) {
          //here is where you can do some drawing
    }

不管怎样,这就是我喜欢做这些事情的方式。就像我说的,这对于你想要的效果来说可能有点过头了但它适用于所有可能需要更多处理的情况

最新更新