Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_jojo3);
bitmapBg = Bitmap.createScaledBitmap(bitmap, mWidth, (int) mSurfaceHeight, true);
(2)如何在屏幕上只画出图像的一部分?
Canvas::drawBitmap中有这样一个函数:
public void drawBitmap(Bitmap bitmap,float left,float top,Paint paint)
这个函数可以指定开始绘制图片的左上角位置。其中left、top就是指从Bitmap的哪个左上角点开始绘制,这样我们就可以指定绘制图片的一部分了。
(3)如何实现Bitmap的左右移动?
我们默从Bitmap的左上角(0,0)开始绘制,然后根据每次的步近距离向右移动,当移动到底时,再返回向左移动,核心代码如下:
//开始绘制的图片的x坐标
private int mBitposX;
//背景移动状态
private enum State {
LEFT, RIGHT
}
//默认为向左
private State state = State.LEFT;
//背景画布移动步伐,设置为1表示每次只移动1px,越大表明移动的越快
private final int BITMAP_STEP = 1;
private void DrawView() {
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mCanvas.drawBitmap(bitmapBg, mBitposX, 0, null);
//滚动效果
switch (state) {
case LEFT:
//画布左移
mBitposX -= BITMAP_STEP;
break;
case RIGHT:
mBitposX += BITMAP_STEP;
break;
default:
break;
}
if (mBitposX <= -mSurfaceWidth / 2) {
state = State.RIGHT;
}
if (mBitposX >= 0) {
state = State.LEFT;
}
}
然后我们需要在初始化的时候就让背景开始运动,所以要添加Surface监听,用flag作为开始、结束动画的标识,在生命周期中使用:
public AnimationSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
flag = true;
startAnimation();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
flag = false;
}
});
}
然后startAnimation函数用来打开动画:
private void startAnimation() {
mSurfaceWidth = getWidth();
mSurfaceHeight = getHeight();
int mWidth = (int) (mSurfaceWidth * 3 / 2);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_jojo3);
bitmapBg = Bitmap.createScaledBitmap(bitmap, mWidth, (int) mSurfaceHeight, true);
thread = new Thread(new Runnable() {
@Override
public void run() {
while (flag) {
mCanvas = surfaceHolder.lockCanvas();
DrawView();
surfaceHolder.unlockCanvasAndPost(mCanvas);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
}
为了减轻主线程的计算负担,我们单独开启一个线程来执行绘图操作;绘图完成后,我们延缓了50ms再进行下次绘图,这样从效果上来看就是一步步移动的。
3、SurfaceView双缓冲技术
(1)概述
SurfaceView的双缓冲技术需要两个图形缓冲区支持,一个是前端缓冲区,一个是后端缓冲区。
前端区对应当前屏幕正在显示的内容,后端缓冲区是接下来渲染的图形缓冲区。
**我们通过surfaceHolder.lockCanvas()函数获得的缓冲区是后端缓冲区。
当绘图完成后,调用surfaceHolder.unlockCanvasAndPost(mCanvas)函数将后端缓冲区与前端缓冲区交换,后端缓冲区变前端缓冲区。**
而原来的前端缓冲区则变成后端缓冲区,等待下一次srufaceHolder.lockCanvas()函数调用返回给用户使用,如此往复。
上面的机制让绘制的效率大大的提高,但这样也产生了一个问题&#x