简体   繁体   English

围绕画布上的枢轴旋转位图

[英]Rotating a bitmap around a pivot on a canvas

I am trying to implement a watch face where a bitmap image of a hand rotates about the center of the face on a canvas. 我正在尝试实现一个表面,其中手的位图图像围绕画布上的脸部中心旋转。

  1. Basically in the onDraw() method, I want to be able to put an image resource onto the canvas then rotate it rotate it every second. 基本上在onDraw()方法中,我希望能够将图像资源放到画布上然后旋转它每秒旋转它。
  2. I have logic in place to trigger the rotation every second, I am not sure how to obtain the image resource and then rotate it. 我有逻辑到每秒触发旋转,我不知道如何获取图像资源,然后旋转它。

Any help would be appriciated! 任何帮助都会得到满足!

Basic steps: 基本步骤:

  1. Decode your bitmap from, for example, Resources, but there are other ways. 例如,从资源中解码您的位图,但还有其他方法。 (You would want to do this once when initializing the class, not on every draw cycle.): (初始化类时,您可能希望执行此操作,而不是在每个绘制周期中执行此操作。):

    Bitmap = mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.watch_face);

  2. Set up a Matrix inside onDraw for the rotation. onDraw设置Matrix以进行旋转。 Something like: 就像是:

    Matrix mMatrix = new Matrix(); mMatrix.setRotate (degreeOfRotation, mBitmap.getWidth()/2, mBitmap.getHeight()/2);

  3. Draw the Bitmap using a method that takes in your Matrix: canvas.drawBitmap(mBitmap, mMatrix, mPaint); 使用接收Matrix的方法绘制位图: canvas.drawBitmap(mBitmap, mMatrix, mPaint);

There are other details. 还有其他细节。 Setting up Paint . 设置Paint You may find you need to use the Matrix's postRotate method instead. 您可能会发现需要使用Matrix的postRotate方法。 Etc. Etc. But this should be enough to you started Googling. 等等。但这应该足以让你开始谷歌搜索。

In this certain situation (I guess you're trying to rotate bitmaps with Google watch face api) you should have in mind rules described in this brilliant post , and avoid using large bitmaps for watch hands. 在这种情况下(我猜你试图用谷歌表面api旋转位图)你应该记住这篇精彩帖子中描述的规则,并避免使用大型位图用于表针。 This means you'll have to specify vertical and horizontal margins. 这意味着您必须指定垂直和水平边距。 I used the solution posted by Jave here . 我在这里使用了Jave发布的解决方案。

yourCanvas.save(Canvas.MATRIX_SAVE_FLAG); //Save the canvas
yourCanvas.rotate(currentRotation, centerX, centerY);
int marginX = (width - yourBitmap.getWidth()) / 2; //Calculate horizontal margin
yourCanvas.drawBitmap(yourBitmap, marginX, 0, yourPaint);
yourCanvas.restore();

I gave up cropping the bitmap vertically, since it's much easier to rotate it this way, but it should be taken in consideration if you want to be in full compliance to the rules. 我放弃了垂直裁剪位图,因为以这种方式旋转它更容易,但如果你想完全符合规则,应该考虑它。 It would be even better not to calculate marginX here. 最好不要在这里计算marginX It may be done in onSurfaceChanged , as described in the post mentioned above. 它可以在onSurfaceChanged中完成,如上面提到的帖子中所述。

I recently needed to solve the bitmap rotation problem for an Android Wear watchface. 我最近需要解决Android Wear表盘的位图旋转问题。 The following onDraw code worked for me. 以下onDraw代码对我有用。 Be sure your bitmaps are scaled before onDraw gets called: 在调用onDraw之前,请确保缩放位图:

        // first draw the background
        if (isInAmbientMode()) {
            canvas.drawColor(Color.BLACK);
        } else {
            if (mBackgroundBitmapScaled == null) {
                canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mBackgroundPaint);
            }
            else {
                canvas.drawBitmap(mBackgroundBitmapScaled, 0, 0, null);
            }
        }

        // now setup to draw the hands..
        float centerX = bounds.width() / 2f;
        float centerY = bounds.height() / 2f;

        float secRot = mCalendar.get(Calendar.SECOND) / 30f * (float) Math.PI;
        int minutes = mCalendar.get(Calendar.MINUTE);
        float minRot = minutes / 30f * (float) Math.PI;
        float hrRot = ((mCalendar.get(Calendar.HOUR) + (minutes / 60f)) / 6f) * (float) Math.PI;

        if (isInAmbientMode()) {
            mHandPaint.clearShadowLayer();
            float minLength = centerX - 40;
            float hrLength = centerX - 80;

            // hour hand
            float hrX = (float) Math.sin(hrRot) * hrLength;
            float hrY = (float) -Math.cos(hrRot) * hrLength;
            canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHandPaint);

            // minute hand
            float minX = (float) Math.sin(minRot) * minLength;
            float minY = (float) -Math.cos(minRot) * minLength;
            canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mHandPaint);
        }
        else {
            // hour hand
            Matrix matrix = new Matrix();
            matrix.setRotate (hrRot / (float) Math.PI * 180, mHourHandBitmapScaled.getWidth()/2, mHourHandBitmapScaled.getHeight()/2);
            canvas.drawBitmap(mHourHandBitmapScaled, matrix, mHandPaint);

            // minute hand
            matrix = new Matrix();
            matrix.setRotate (minRot / (float) Math.PI * 180, mHourHandBitmapScaled.getWidth()/2, mHourHandBitmapScaled.getHeight()/2);
            canvas.drawBitmap(mMinuteHandBitmapScaled, matrix, mHandPaint);
        }

        if (!mAmbient) {
            // second hand
            float secLength = centerX - 20;
            float secX = (float) Math.sin(secRot) * secLength;
            float secY = (float) -Math.cos(secRot) * secLength;
            canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mHandPaint);
        }

and for scaling: 并用于缩放:

    private void scaleWatchFace(int width, int height) {
        Log.v(TAG, "scaleWatchFace");
        mBackgroundBitmapScaled = Bitmap.createScaledBitmap(mBackgroundBitmap, width, height, true /* filter */);
        float ratio = (float) width / mBackgroundBitmap.getWidth();
        mMinuteHandBitmapScaled = Bitmap.createScaledBitmap(mMinuteHandBitmap,
                (int) (mMinuteHandBitmap.getWidth() * ratio),
                (int) (mMinuteHandBitmap.getHeight() * ratio), true);
        mHourHandBitmapScaled = Bitmap.createScaledBitmap(mHourHandBitmap,
                (int) (mHourHandBitmap.getWidth() * ratio),
                (int) (mHourHandBitmap.getHeight() * ratio), true);
    }

Note that the image sizes of my background and watch hand resources are all 480x480. 请注意,我的背景和手表资源的图像大小都是480x480。 That eliminates any need for translation to center, and (possibly) is easier on the battery. 这消除了转换到中心的任何需要,并且(可能)更容易使用电池。

I hope this is useful. 我希望这很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM