Since Android 3.0, we have the possibility to set basic 3D transformations to Views using setRotationX and setRotationY, for instance.
In a specific case, I would need to achieve a complex transformation that is rotating around a distant pivot point then scaling on a different pivot point. This is not possible simply by using setScaleX/Y and setRotationX/Y since they share the same pivot point.
Does any simple way exist to provide the desired matrix to the view for display?
For now, I have found two possible workarounds:
Set up a rotation matrix then use it to map a {0,0} point; apply the resulting point to the View's translation then use the View's setScaleX/Y to set the scaling
Hack the View's onDraw and apply the transformation on the canvas. Add the logic to reverse map touch events, too.
Both are not really convenient since I am building an AdapterView which displays its items using a configurable effect; for example, it can be possible to switch the effect to have the items arrranged in a circle or like a "cover flow".
The 4 by 4 transformation matrix uses homogeneous coordinates, which allow to distinguish between points and vectors. Vectors have a direction and magnitude whereas points are positions specified by 3 coordinates with respect to the origin and three base vectors i, j and k that are stored in the first three columns.
Transformation Matrix is a matrix that transforms one vector into another vector by the process of matrix multiplication. The transformation matrix alters the cartesian system and maps the coordinates of the vector to the new coordinates.
I, too, am wracking my brain over this. This is the best I've come up with (super hacky):
MyAnimation animation = new MyAnimation(matrix);
animation.setDuration(0);
animation.setFillAfter(true);
view.setAnimation(animation);
The animation solution above works but it results in infinite calls to applyTransformation
which leaves a little to be desired from an efficiency standpoint. In addition if you kill the animation the matrix applied isn't permanent to the view so you're forced into letting it run forever. Here's an alternative less hacky approach that results in only a single call to setMatrix
each time invalidate()
on the view is called:
In the parents view constructor:
setStaticTransformationsEnabled(true);
Then in the body:
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
// apply transform to child view - child triggers this call by call to `invalidate()`
t.getMatrix().set(someMatrix);
return true;
}
Simply call invalidate()
on the child anytime you want to update it's matrix.
xtravar's answer is great, and MyAnimation implementation is here
private class MyAnimation extends Animation {
private Matrix matrix;
public MyAnimation(Matrix matrix) {
this.matrix = matrix;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
t.getMatrix().set(matrix);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With