【问题标题】:What is the most efficient way to rotate and display an image in an Android UI?在 Android UI 中旋转和显示图像的最有效方法是什么?
【发布时间】:2015-10-18 23:43:30
【问题描述】:

我想经常(每秒多次)旋转一张图像显示它。为此,必须缩放图像以适合视图。

我首先做的是定义一个 Drawable,将其加载到 ImageView 中并调用 setRotation()。但它只是从 API 级别 11 开始支持,而不是 9。

<ImageView
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:src="@drawable/image" />

这给出了非常糟糕的性能(如预期的那样),但是最有效/最合适的方法是什么?图像包含透明区域,如果这很重要的话。我应该使用硬件加速吗?

This 答案与此主题有某种关联。但就我而言,旋转必须进行多次,而缩放只需进行一次。

在我工作了一段时间后,我卡在了这一点上,并在这里寻求帮助。如果您还有其他问题,请发表评论,我会很乐意回答。

【问题讨论】:

  • 这个旋转是恒定的动画,还是由用户手势控制的旋转角度,还是...?
  • 它是由传感器控制的,所以它不是恒定的。 @克里斯

标签: java android performance drawing image-rotation


【解决方案1】:

我假设您的传感器读数是 push 模型,您可以在其中设置一个侦听器以检测传感器的变化,而不是 pull(轮询)模型.我还将假设回调发生在非 UI 线程上(如果不是,它应该)。

由于您正在旋转图像,我还假设您的源位图是圆形图像,例如表盘上的针等。

  • 创建一个View 子类。我会叫它SensorView。您将自己进行绘图,因此您不需要ImageView
  • 您的传感器回调将需要对活动的引用或有某种方式在 UI 线程上运行更新。
  • 当您的传感器触发时,获取读数并将其设置在视图上。

    actviity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mSensorView.setReading(val);
        }
    });
    
  • SensorView 将有一个值用于读取,Bitmap 用于图像,Matrix 用于转换位图。

    public class SensorView extends View {
    
        private float mReading;  // I use float as an example; use whatever your sensor device supports
        private Bitmap mBitmap;
        private Matrix mMatrix;
        private RectF mBitmapRect;
        private RectF mViewRect;
    
        public SensorView(Context context) {
            this(context, null);
        }
    
        public SensorView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            // set up your Bitmap here; don't worry about scaling it yet
            mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.sensor_bitmap);
    
            mMatrix = new Matrix();
            mBitmapRect = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
            mViewRect = new RectF();
        }
    
        public void setReading(float reading) {
            mReading = reading;
            postInvalidate();   // refresh the display
        }
    
        @Override
        public void onDraw(Canvas canvas) {
    
            mViewRect.right = getWidth();
            mViewRect.bottom = getHeight();
            mMatrix.reset();
    
            // center and scale the image
            mMatrix.setRectToRect(mBitmapRect, mViewRect, ScaleToFit.CENTER);
    
            // do the rotation
            float theta = ... // compute angle based on mReading
            mMatrix.preRotate(theta, mBitmapRect.centerX(), mBitmapRect.centerY());
    
            // draw the bitmap with the matrix
            canvas.drawBitmap(mBitmap, mMatrix, null);
        }
    }
    

[经过一些测试编辑]

【讨论】:

  • 好的,谢谢!这似乎比我的“解决方案”更简单,并且带走了处理程序。我会尽快测试它!
  • 如果您遇到问题,请告诉我。我将自己测试它。
  • 嘿@felixd,我有一个小错字(Content),我对非 UI 线程有误,setReading() 必须在 UI 线程上运行。请参阅我的更新答案。如果您在使用它时遇到任何问题,请使用您的所有新代码更新您的问题,我会查看它。
  • 为什么必须从那里调用它?文档说:导致在事件循环的后续循环中发生无效。使用它来使来自非 UI 线程的视图无效。 仅当此视图附加到窗口时,才能从 UI 线程外部调用此方法
  • 所以我认为它也可以,但 Android Studio 编译器抱怨因为我从非 UI 线程调用 View 上的方法。他们只是假设View 上的任何方法都有 UI 操作。也许有一个注释可以抑制它,必须调查。
猜你喜欢
  • 2013-03-29
  • 2012-06-12
  • 1970-01-01
  • 2015-03-14
  • 2013-11-28
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 2011-06-05
相关资源
最近更新 更多