1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package androidx.constraintlayout.utils.widget; 17 18 import android.content.Context; 19 import android.content.res.TypedArray; 20 import android.graphics.Canvas; 21 import android.graphics.Color; 22 import android.graphics.Matrix; 23 import android.graphics.Paint; 24 import android.util.AttributeSet; 25 import android.view.ViewParent; 26 27 import androidx.constraintlayout.motion.widget.MotionLayout; 28 import androidx.constraintlayout.widget.R; 29 30 import org.jspecify.annotations.NonNull; 31 32 /** 33 * A view that is useful for prototyping Views that will move in MotionLayout. <b>Added in 2.0</b> 34 * <p> 35 * This view works with MotionLayout to demonstrate the motion of 25 points on the view. 36 * It is based on MockView which draws a label (by default the view id), 37 * along with diagonals. 38 * 39 * Useful as a deeper understanding of the motion of a view in a MotionLayout 40 * 41 * </p> 42 */ 43 public class MotionTelltales extends MockView { 44 private static final String TAG = "MotionTelltales"; 45 private Paint mPaintTelltales = new Paint(); 46 MotionLayout mMotionLayout; 47 float[] mVelocity = new float[2]; 48 Matrix mInvertMatrix = new Matrix(); 49 int mVelocityMode = MotionLayout.VELOCITY_POST_LAYOUT; 50 int mTailColor = Color.MAGENTA; 51 float mTailScale = 0.25f; 52 MotionTelltales(Context context)53 public MotionTelltales(Context context) { 54 super(context); 55 init(context, null); 56 } 57 MotionTelltales(Context context, AttributeSet attrs)58 public MotionTelltales(Context context, AttributeSet attrs) { 59 super(context, attrs); 60 init(context, attrs); 61 } 62 MotionTelltales(Context context, AttributeSet attrs, int defStyleAttr)63 public MotionTelltales(Context context, AttributeSet attrs, int defStyleAttr) { 64 super(context, attrs, defStyleAttr); 65 init(context, attrs); 66 } 67 init(Context context, AttributeSet attrs)68 private void init(Context context, AttributeSet attrs) { 69 if (attrs != null) { 70 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MotionTelltales); 71 final int count = a.getIndexCount(); 72 for (int i = 0; i < count; i++) { 73 int attr = a.getIndex(i); 74 if (attr == R.styleable.MotionTelltales_telltales_tailColor) { 75 mTailColor = a.getColor(attr, mTailColor); 76 } else if (attr == R.styleable.MotionTelltales_telltales_velocityMode) { 77 mVelocityMode = a.getInt(attr, mVelocityMode); 78 } else if (attr == R.styleable.MotionTelltales_telltales_tailScale) { 79 mTailScale = a.getFloat(attr, mTailScale); 80 } 81 } 82 a.recycle(); 83 } 84 mPaintTelltales.setColor(mTailColor); 85 mPaintTelltales.setStrokeWidth(5); 86 } 87 88 @Override onAttachedToWindow()89 protected void onAttachedToWindow() { 90 super.onAttachedToWindow(); 91 92 } 93 94 /** 95 * set the text 96 * @param text 97 */ setText(CharSequence text)98 public void setText(CharSequence text) { 99 mText = text.toString(); 100 requestLayout(); 101 } 102 103 @Override onLayout(boolean changed, int left, int top, int right, int bottom)104 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 105 super.onLayout(changed, left, top, right, bottom); 106 postInvalidate(); 107 } 108 109 @Override onDraw(@onNull Canvas canvas)110 public void onDraw(@NonNull Canvas canvas) { 111 super.onDraw(canvas); 112 Matrix matrix = getMatrix(); 113 matrix.invert(mInvertMatrix); 114 if (mMotionLayout == null) { 115 ViewParent vp = getParent(); 116 if (vp instanceof MotionLayout) { 117 mMotionLayout = (MotionLayout) vp; 118 } 119 return; 120 } 121 int width = getWidth(); 122 int height = getHeight(); 123 float[] f = {0.1f, 0.25f, 0.5f, 0.75f, 0.9f}; 124 for (int y = 0; y < f.length; y++) { 125 float py = f[y]; 126 for (int x = 0; x < f.length; x++) { 127 float px = f[x]; 128 mMotionLayout.getViewVelocity(this, px, py, mVelocity, mVelocityMode); 129 mInvertMatrix.mapVectors(mVelocity); 130 131 float sx = (width * px); 132 float sy = (height * py); 133 float ex = sx - (mVelocity[0] * mTailScale); 134 float ey = sy - (mVelocity[1] * mTailScale); 135 mInvertMatrix.mapVectors(mVelocity); 136 canvas.drawLine(sx, sy, ex, ey, mPaintTelltales); 137 } 138 139 } 140 } 141 } 142