【问题标题】:Rotating a bitmap around a pivot on a canvas围绕画布上的枢轴旋转位图
【发布时间】:2014-12-25 06:27:56
【问题描述】:

我正在尝试实现一个表盘,其中手的位图图像围绕画布上的面部中心旋转。

  1. 基本上在 onDraw() 方法中,我希望能够将图像资源放在画布上,然后旋转它每秒旋转一次。
  2. 我有每秒触发一次旋转的逻辑,我不确定如何获取图像资源然后旋转它。

如有任何帮助,我们将不胜感激!

【问题讨论】:

    标签: android android-layout wear-os sony-smartwatch


    【解决方案1】:

    基本步骤:

    1. 例如从资源中解码您的位图,但还有其他方法。 (您可能希望在初始化类时执行一次,而不是在每个绘制周期。):

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

    2. onDraw 内设置Matrix 用于旋转。比如:

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

    3. 使用接受矩阵的方法绘制位图: canvas.drawBitmap(mBitmap, mMatrix, mPaint);

    还有其他细节。设置Paint。您可能会发现需要改用 Matrix 的 postRotate 方法。等等等等。但这应该足以让您开始使用 Google 搜索。

    【讨论】:

    • 枢轴位置不变。
    【解决方案2】:

    在这种特定情况下(我猜您正在尝试使用 Google watch face api 旋转位图)您应该牢记this brilliant post 中描述的规则,并避免将大位图用于手表指针。这意味着您必须指定垂直和水平边距。我使用了 Jave here 发布的解决方案。

    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();
    

    我放弃了垂直裁剪位图,因为这样旋转它更容易,但如果你想完全遵守规则,应该考虑它。最好不要在这里计算marginX。可以在onSurfaceChanged完成,如上文所述。

    【讨论】:

      【解决方案3】:

      我最近需要解决 Android Wear 表盘的位图旋转问题。 以下 onDraw 代码对我有用。确保在调用 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);
              }
      

      对于缩放:

          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);
          }
      

      请注意,我的背景和手表资源的图像尺寸都是 480x480。 这消除了任何需要转换到中心的需要,并且(可能)更容易使用电池。

      我希望这是有用的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-03
        • 2015-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多