在Android画布上绘制旋转位图的最佳方法是什么?

时间:2013-11-15 09:46:52

标签: android graphics bitmap android-canvas surfaceview

我正在开发一个应用程序,我们手动滚动一些星图。所以我不必抽象地谈论,这里是有问题的应用程序:https://play.google.com/store/apps/details?id=com.tw.fireballs

如果您查看商店列表,您可以看到我们使用地平线上方的图像...主要是因为它看起来非常漂亮。这对于较低分辨率的设备来说不是问题,由于所涉及的像素数量较少,它们似乎没有遇到很大的问题。在像我的HTC One或我的妻子Nexus 5这样的更高分辨率的设备上,屏幕上有一个很大的帧率下降。它不足以阻止我释放它,但如果可能的话,我想改进它。

我目前正在使用SurfaceView,并绘制到由mSurfaceHolder.lockCanvas(null)获取的画布,因此它不是硬件加速的。我尝试将它作为常规视图实现,但总的来说它实际上变慢了,所以在我进入OpenGL领域之前,我想探索是否有什么可以做些什么来加快这一点。

基本上,我们从地平线上的薄(不透明)图像“切片”开始,将其缩放到屏幕对角线的大小,并将其旋转以匹配设备的方向。

绘图代码如下:

private void loadResources() {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    mHorizonImage = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.star_map_background, options);
}

@Override
public void updateDimensions(int width, int height) {
    super.updateDimensions(width, height);

    int horizonHeight = mCanvasHeight / 3;
    int horizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));

    mHorizonImage = Bitmap.createScaledBitmap(mHorizonImage, horizonWidth, horizonHeight, false);
}

@Override
public void drawOn(Canvas canvas) {
    double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
    double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
    double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));

    float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
    float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));

    canvas.save();
    canvas.translate(x, y);
    canvas.rotate((float) mOrientation.tilt);
    canvas.drawBitmap(mHorizonImage, -mHorizonImage.getWidth() / 2, -mHorizonImage.getHeight(), null);
    canvas.restore();
}

有没有更有效的方法来做到这一点,不受屏幕分辨率的影响?我们围绕着一些想法,但是我很想听到比我更了解这些东西的人。如果您有任何问题,请询问,我将非常感激您的帮助。

干杯, 森

1 个答案:

答案 0 :(得分:1)

@pskink击中头部的钉子。使用Matrix参数绘制位图比我正在经历的缩放位图和画布旋转更高效。在像我的HTC One这样的1080P设备上,如果我把手机放在对角线上,我常常会看到帧率从50+降到10。现在,如果它下降了5,我会很幸运。

修改后的代码现在看起来像:

@Override
public void updateDimensions(int width, int height) {
    super.updateDimensions(width, height);

    mHorizonHeight = mCanvasHeight / 3;
    mHeightScale = (float)mHorizonHeight / (float)mHorizonImage.getHeight();

    mHorizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));
    mWidthScale = (float)mHorizonWidth / (float)mHorizonImage.getWidth();
}

@Override
public void drawOn(Canvas canvas) {
    double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
    double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
    double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));

    float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
    float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));

    mDrawMatrix.reset();
    mDrawMatrix.postScale(mWidthScale, mHeightScale);
    mDrawMatrix.postTranslate(x - mHorizonWidth / 2, y - mHorizonHeight);
    mDrawMatrix.postRotate((float) mOrientation.tilt, x, y);
    canvas.drawBitmap(mHorizonImage, mDrawMatrix, null);
    canvas.save();
}