Android: применить произвольное преобразование к представлению

Я хотел бы взять произвольную матрицу и применить ее к android.views.View.

Единственный надежный способ, который я нашел, – это взломать:

MyAnimation animation = new MyAnimation(matrix); animation.setDuration(0); animation.setFillAfter(true); view.setAnimation(animation); 

Есть ли способ лучше? Я пытался использовать getChildStaticTransformation и помещать его в родителя, но это не сработало (возможно, я делал это неправильно?)

В конце концов, я создал свой собственный макет, основанный на AbsoluteLayout, добавил матрицу в свои LayoutParams, используя getChildStaticTransformation и перегрузил dispatchTouchEvent, чтобы мой ребенок мог ответить на правильные границы при повороте. Гораздо сложнее, чем я ожидал.

 public class UIViewLayout extends ViewGroup { @Override protected boolean getChildStaticTransformation(View child, Transformation t) { if(child instanceof UIViewLayout) { t.getMatrix().reset(); UIViewLayout.LayoutParams params = (UIViewLayout.LayoutParams)child.getLayoutParams(); t.setTransformationType(Transformation.TYPE_MATRIX); t.getMatrix().set(params.matrix); } return true; } public UIViewLayout(android.content.Context context) { super(context); this.setClipChildren(false); this.setClipToPadding(false); this.setChildrenDrawingOrderEnabled(true); this.setStaticTransformationsEnabled(true); } public UIViewLayout(Context context, AttributeSet attrs) { super(context, attrs); } public UIViewLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; // Find out how big everyone wants to be measureChildren(widthMeasureSpec, heightMeasureSpec); // Find rightmost and bottom-most child for (int i = 0; i < count; i++) { View child = getChildAt(i); if (child.getVisibility() != GONE) { int childRight; int childBottom; UIViewLayout.LayoutParams lp = (UIViewLayout.LayoutParams) child.getLayoutParams(); childRight = lp.x + child.getMeasuredWidth(); childBottom = lp.y + child.getMeasuredHeight(); maxWidth = Math.max(maxWidth, childRight); maxHeight = Math.max(maxHeight, childBottom); } } // Account for padding too //maxWidth += mPaddingLeft + mPaddingRight; //maxHeight += mPaddingTop + mPaddingBottom; // Check against minimum height and width maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0), resolveSizeAndState(maxHeight, heightMeasureSpec, 0)); } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); if (child.getVisibility() != GONE) { UIViewLayout.LayoutParams lp = (UIViewLayout.LayoutParams) child.getLayoutParams(); int childLeft = lp.x; int childTop = lp.y; child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new UIViewLayout.LayoutParams(getContext(), attrs); } // Override to allow type-checking of LayoutParams. @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof UIViewLayout.LayoutParams; } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); } @Override public boolean shouldDelayChildPressedState() { return false; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { for(int i = 0; i < this.getChildCount(); i++) { View child = getChildAt(i); if(child instanceof UIViewLayout) { UIViewLayout.LayoutParams params = (UIViewLayout.LayoutParams)child.getLayoutParams(); if(!params.matrix.isIdentity()) { MotionEvent ev2 = MotionEvent.obtain(ev); ev2.setLocation(ev2.getX() - params.x, ev2.getY() - params.y); Matrix m = new Matrix(); params.matrix.invert(m); ev2.transform(m); if(child.dispatchTouchEvent(ev2)) { return true; } ev2.recycle(); } } } return super.dispatchTouchEvent(ev); } public static class LayoutParams extends ViewGroup.LayoutParams { public int x; public int y; public Matrix matrix; public LayoutParams(int width, int height, int x, int y) { super(width, height); this.x = x; this.y = y; this.matrix = new Matrix(); } public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } public LayoutParams(ViewGroup.LayoutParams source) { super(source); } } }