1058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar/* 2058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 3058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * 4058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * you may not use this file except in compliance with the License. 6058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * You may obtain a copy of the License at 7058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * 8058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * 10058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * See the License for the specific language governing permissions and 14058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * limitations under the License. 15058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 16058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 1793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banespackage android.support.v7.graphics.drawable; 18058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 21058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.content.Context; 22058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.content.res.TypedArray; 23058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Canvas; 24058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.ColorFilter; 25058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Paint; 26058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Path; 27058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.PixelFormat; 28058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Rect; 29058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.drawable.Drawable; 30fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banesimport android.support.annotation.ColorInt; 3193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport android.support.annotation.FloatRange; 3293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport android.support.annotation.IntDef; 33c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 34b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 35b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banesimport android.support.v4.view.ViewCompat; 36058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.support.v7.appcompat.R; 37058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 3893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport java.lang.annotation.Retention; 3993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport java.lang.annotation.RetentionPolicy; 4093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 41058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar/** 4293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * A drawable that can draw a "Drawer hamburger" menu or an arrow and animate between them. 4393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * <p> 4493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * The progress between the two states is controlled via {@link #setProgress(float)}. 4593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * </p> 46058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 4793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banespublic class DrawerArrowDrawable extends Drawable { 4893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 4993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 50b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point towards the left. 5193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * 5293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #setDirection(int) 5393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #getDirection() 5493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 5593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public static final int ARROW_DIRECTION_LEFT = 0; 5693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 5793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 58b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point towards the right. 5993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * 6093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #setDirection(int) 6193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #getDirection() 6293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 6393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public static final int ARROW_DIRECTION_RIGHT = 1; 6493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 65b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes /** 66b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point towards the start. 67b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 68b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * <p>When used in a view with a {@link ViewCompat#LAYOUT_DIRECTION_RTL RTL} layout direction, 69b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * this is the same as {@link #ARROW_DIRECTION_RIGHT}, otherwise it is the same as 70b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * {@link #ARROW_DIRECTION_LEFT}.</p> 71b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 72b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #setDirection(int) 73b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #getDirection() 74b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes */ 75b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes public static final int ARROW_DIRECTION_START = 2; 76b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 77b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes /** 78b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point to the end. 79b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 80b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * <p>When used in a view with a {@link ViewCompat#LAYOUT_DIRECTION_RTL RTL} layout direction, 81b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * this is the same as {@link #ARROW_DIRECTION_LEFT}, otherwise it is the same as 82b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * {@link #ARROW_DIRECTION_RIGHT}.</p> 83b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 84b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #setDirection(int) 85b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #getDirection() 86b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes */ 87b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes public static final int ARROW_DIRECTION_END = 3; 88b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 8993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** @hide */ 908e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas @RestrictTo(LIBRARY_GROUP) 91b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes @IntDef({ARROW_DIRECTION_LEFT, ARROW_DIRECTION_RIGHT, 92b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes ARROW_DIRECTION_START, ARROW_DIRECTION_END}) 9393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes @Retention(RetentionPolicy.SOURCE) 9493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public @interface ArrowDirection {} 95058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 96058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private final Paint mPaint = new Paint(); 97058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 98c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas // The angle in degrees that the arrow head is inclined at. 99058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private static final float ARROW_HEAD_ANGLE = (float) Math.toRadians(45); 100058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The length of top and bottom bars when they merge into an arrow 101fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mArrowHeadLength; 102058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The length of middle bar 103fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mBarLength; 104058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The length of the middle bar when arrow is shaped 105fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mArrowShaftLength; 106058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The space between bars when they are parallel 107fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mBarGap; 108058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Whether bars should spin or not during progress 109fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private boolean mSpin; 110058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Use Path instead of canvas operations so that if color has transparency, overlapping sections 111058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // wont look different 112058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private final Path mPath = new Path(); 113058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The reported intrinsic size of the drawable. 114058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private final int mSize; 115058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Whether we should mirror animation when animation is reversed. 116058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private boolean mVerticalMirror = false; 117058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The interpolated version of the original progress 118058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private float mProgress; 1199ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // the amount that overlaps w/ bar size when rotation is max 1209ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar private float mMaxCutForBarSize; 12193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes // The arrow direction 122b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes private int mDirection = ARROW_DIRECTION_START; 123058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 124058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar /** 125058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * @param context used to get the configuration for the drawable from 126058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 12793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public DrawerArrowDrawable(Context context) { 128fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStyle(Paint.Style.STROKE); 129fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStrokeJoin(Paint.Join.MITER); 130fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStrokeCap(Paint.Cap.BUTT); 131058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPaint.setAntiAlias(true); 132fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 133fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final TypedArray a = context.getTheme().obtainStyledAttributes(null, 134fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes R.styleable.DrawerArrowToggle, R.attr.drawerArrowStyle, 135fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes R.style.Base_Widget_AppCompat_DrawerArrowToggle); 136fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 137fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setColor(a.getColor(R.styleable.DrawerArrowToggle_color, 0)); 138fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setBarThickness(a.getDimension(R.styleable.DrawerArrowToggle_thickness, 0)); 139fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setSpinEnabled(a.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true)); 1409ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // round this because having this floating may cause bad measurements 141fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setGapSize(Math.round(a.getDimension(R.styleable.DrawerArrowToggle_gapBetweenBars, 0))); 142fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 143fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mSize = a.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0); 1449ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // round this because having this floating may cause bad measurements 145fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mBarLength = Math.round(a.getDimension(R.styleable.DrawerArrowToggle_barLength, 0)); 1469ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // round this because having this floating may cause bad measurements 147fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowHeadLength = Math.round(a.getDimension( 148fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes R.styleable.DrawerArrowToggle_arrowHeadLength, 0)); 149fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowShaftLength = a.getDimension(R.styleable.DrawerArrowToggle_arrowShaftLength, 0); 15093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes a.recycle(); 151fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 152058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 153fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 154fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the length of the arrow head (from tip to edge, perpendicular to the shaft). 155fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 156fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param length the length in pixels 157fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 158fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setArrowHeadLength(float length) { 159fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mArrowHeadLength != length) { 160fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowHeadLength = length; 161fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 162fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 163fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 164fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 165fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 166fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the length of the arrow head (from tip to edge, perpendicular to the shaft), 167fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * in pixels. 168fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 169fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getArrowHeadLength() { 170fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mArrowHeadLength; 171fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 172fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 173fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 174fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the arrow shaft length. 175fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 176fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param length the length in pixels 177fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 178fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setArrowShaftLength(float length) { 179fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mArrowShaftLength != length) { 180fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowShaftLength = length; 181fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 182fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 183fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 184fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 185fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 186fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the arrow shaft length in pixels. 187fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 188fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getArrowShaftLength() { 189fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mArrowShaftLength; 190fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 191fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 192fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 193fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * The length of the bars when they are parallel to each other. 194fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 195fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getBarLength() { 196fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mBarLength; 197fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 198fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 199fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 200fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the length of the bars when they are parallel to each other. 201fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 202fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param length the length in pixels 203fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 204fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setBarLength(float length) { 205fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mBarLength != length) { 206fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mBarLength = length; 207fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 208fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 209fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 210fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 211fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 212fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the color of the drawable. 213fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 214fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setColor(@ColorInt int color) { 215fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (color != mPaint.getColor()) { 216fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setColor(color); 217fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 218fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 219fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 220fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 221fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 222fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the color of the drawable. 223fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 224fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes @ColorInt 225fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public int getColor() { 226fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mPaint.getColor(); 227fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 228fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 229fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 230fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the thickness (stroke size) for the bars. 231fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 232fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param width stroke width in pixels 233fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 234fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setBarThickness(float width) { 235fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mPaint.getStrokeWidth() != width) { 236fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStrokeWidth(width); 237fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mMaxCutForBarSize = (float) (width / 2 * Math.cos(ARROW_HEAD_ANGLE)); 238fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 239fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 240fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 241fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 242fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 243fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the thickness (stroke width) of the bars. 244fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 245fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getBarThickness() { 246fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mPaint.getStrokeWidth(); 247fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 248fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 249fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 250fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the max gap between the bars when they are parallel to each other. 251fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 252fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #getGapSize() 253fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 254fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getGapSize() { 255fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mBarGap; 256fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 2579ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar 258fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 259fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the max gap between the bars when they are parallel to each other. 260fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 261fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param gap the gap in pixels 262fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 263fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #getGapSize() 264fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 265fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setGapSize(float gap) { 266fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (gap != mBarGap) { 267fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mBarGap = gap; 268fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 269fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 270058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 271058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 27293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 27393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Set the arrow direction. 27493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 27593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setDirection(@ArrowDirection int direction) { 27693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes if (direction != mDirection) { 27793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes mDirection = direction; 27893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes invalidateSelf(); 27993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 28093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 28193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 28293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 283fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns whether the bars should rotate or not during the transition. 284fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 285fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #setSpinEnabled(boolean) 286fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 287fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public boolean isSpinEnabled() { 288fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mSpin; 289fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 290fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 291fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 292fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns whether the bars should rotate or not during the transition. 293fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 294fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param enabled true if the bars should rotate. 295fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 296fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #isSpinEnabled() 297fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 298fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setSpinEnabled(boolean enabled) { 299fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mSpin != enabled) { 300fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mSpin = enabled; 301fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 302fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 303fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 304fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 305fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 30693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Returns the arrow direction. 30793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 30893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes @ArrowDirection 30993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public int getDirection() { 31093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes return mDirection; 31193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 312058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 313058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar /** 314058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * If set, canvas is flipped when progress reached to end and going back to start. 315058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 31693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setVerticalMirror(boolean verticalMirror) { 31793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes if (mVerticalMirror != verticalMirror) { 31893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes mVerticalMirror = verticalMirror; 31993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes invalidateSelf(); 32093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 321058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 322058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 323058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 324058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public void draw(Canvas canvas) { 325058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar Rect bounds = getBounds(); 326b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 327b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes final boolean flipToPointRight; 328b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes switch (mDirection) { 329b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_LEFT: 330b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = false; 331b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 332b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_RIGHT: 333b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = true; 334b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 335b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_END: 336b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = DrawableCompat.getLayoutDirection(this) 337b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes == ViewCompat.LAYOUT_DIRECTION_LTR; 338b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 339b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_START: 340b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes default: 341b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = DrawableCompat.getLayoutDirection(this) 342b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes == ViewCompat.LAYOUT_DIRECTION_RTL; 343b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 344b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes } 345b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 346058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Interpolated widths of arrow bars 347fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 348fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes float arrowHeadBarLength = (float) Math.sqrt(mArrowHeadLength * mArrowHeadLength * 2); 349fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes arrowHeadBarLength = lerp(mBarLength, arrowHeadBarLength, mProgress); 350fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowShaftLength = lerp(mBarLength, mArrowShaftLength, mProgress); 351058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Interpolated size of middle bar 352fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowShaftCut = Math.round(lerp(0, mMaxCutForBarSize, mProgress)); 353058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The rotation of the top and bottom bars (that make the arrow head) 354058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar final float rotation = lerp(0, ARROW_HEAD_ANGLE, mProgress); 355058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 356058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The whole canvas rotates as the transition happens 35793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes final float canvasRotate = lerp(flipToPointRight ? 0 : -180, 35893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes flipToPointRight ? 180 : 0, mProgress); 35993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 360fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowWidth = Math.round(arrowHeadBarLength * Math.cos(rotation)); 361fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowHeight = Math.round(arrowHeadBarLength * Math.sin(rotation)); 3629ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar 363058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.rewind(); 364fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float topBottomBarOffset = lerp(mBarGap + mPaint.getStrokeWidth(), -mMaxCutForBarSize, 3659ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar mProgress); 366058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 367fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowEdge = -arrowShaftLength / 2; 368058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // draw middle bar 369fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPath.moveTo(arrowEdge + arrowShaftCut, 0); 370fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPath.rLineTo(arrowShaftLength - arrowShaftCut * 2, 0); 371058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 3729ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // bottom bar 373058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.moveTo(arrowEdge, topBottomBarOffset); 374058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.rLineTo(arrowWidth, arrowHeight); 375058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 3769ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // top bar 377058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.moveTo(arrowEdge, -topBottomBarOffset); 378058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.rLineTo(arrowWidth, -arrowHeight); 3799ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar 380058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.close(); 381058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 382058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar canvas.save(); 383fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 384058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Rotate the whole canvas if spinning, if not, rotate it 180 to get 385058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // the arrow pointing the other way for RTL. 386fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float barThickness = mPaint.getStrokeWidth(); 387fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final int remainingSpace = (int) (bounds.height() - barThickness * 3 - mBarGap * 2); 388fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes float yOffset = (remainingSpace / 4) * 2; // making sure it is a multiple of 2. 389ad1b0e82100ee31e70040d77bfa4d847b2bf0864Aurimas Liutikas yOffset += barThickness * 1.5f + mBarGap; 390fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 391fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes canvas.translate(bounds.centerX(), yOffset); 392058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar if (mSpin) { 39393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes canvas.rotate(canvasRotate * ((mVerticalMirror ^ flipToPointRight) ? -1 : 1)); 39493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } else if (flipToPointRight) { 3959ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar canvas.rotate(180); 396058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 397058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar canvas.drawPath(mPath, mPaint); 398058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 399058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar canvas.restore(); 400058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 401058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 402058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 40393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setAlpha(int alpha) { 404486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes if (alpha != mPaint.getAlpha()) { 405486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes mPaint.setAlpha(alpha); 406486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes invalidateSelf(); 407486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes } 408058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 409058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 410058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 411058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public void setColorFilter(ColorFilter colorFilter) { 412058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPaint.setColorFilter(colorFilter); 413486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes invalidateSelf(); 414058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 415058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 416058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 417058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public int getIntrinsicHeight() { 418058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return mSize; 419058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 420058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 421058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 422058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public int getIntrinsicWidth() { 423058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return mSize; 424058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 425058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 426058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 427058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public int getOpacity() { 428058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return PixelFormat.TRANSLUCENT; 429058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 430058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 43193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 43293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Returns the current progress of the arrow. 43393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 43493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes @FloatRange(from = 0.0, to = 1.0) 435058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public float getProgress() { 436058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return mProgress; 437058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 438058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 43993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 44093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Set the progress of the arrow. 44193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * 44244ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls * <p>A value of {@code 0.0} indicates that the arrow should be drawn in its starting 44344ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls * position. A value of {@code 1.0} indicates that the arrow should be drawn in its ending 44493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * position.</p> 44593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 44693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { 447486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes if (mProgress != progress) { 448486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes mProgress = progress; 449486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes invalidateSelf(); 450486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes } 451058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 452058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 453058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar /** 454403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes * Returns the paint instance used for all drawing. 455403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes */ 456403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes public final Paint getPaint() { 457403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes return mPaint; 458403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes } 459403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes 460403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes /** 461058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * Linear interpolate between a and b with parameter t. 462058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 463058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private static float lerp(float a, float b, float t) { 464058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return a + (b - a) * t; 465058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 466058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar}