I want to rotate an image often (multiple times a second) and display it. In preparation to this, the image must be scaled to fit the View.
What I first did, was defining a Drawable, loading it into a ImageView and calling setRotation(). But it's only supportet since API level 11 and not 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 gives a very bad perfomance (as expected), but what is the most effcient/suitable way to do this? The image contains transparent areas, if that is important. Should I use hardware acceleration?
This answer is somehow related to this topic. But in my case, the rotation has to be done multiple times while the scaling has to be done only once.
I am stuck at this point after I worked on it for quite a while, and seek assistance here. Please comment if you have further questions, I will happily answer them.
I'll assume your sensor reading is a push model, where you set up a listener for changes to the sensor, as opposed to a pull (polling) model. I'll also assume that the callback happens on an off-UI thread (if it isn't, it should).
Since you are rotating the image I'll also assume that your source bitmap is a circular image like a needle on a dial, etc.
View
subclass. I'll call it SensorView
. You will be doing the drawing yourself, so you don't really need an ImageView
.When your sensor fires, get the reading and set it on the view.
actviity.runOnUiThread(new Runnable() {
@Override
public void run() {
mSensorView.setReading(val);
}
});
The SensorView
will have a value for the reading, a Bitmap
for the image, and a Matrix
for transforming the bitmap.
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);
}
}
[edited after a bit of testing]