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 19058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.content.Context; 20058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.content.res.TypedArray; 21058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Canvas; 22058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.ColorFilter; 23058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Paint; 24058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Path; 25058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.PixelFormat; 26058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.Rect; 27058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.graphics.drawable.Drawable; 28fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banesimport android.support.annotation.ColorInt; 2993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport android.support.annotation.FloatRange; 3093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport android.support.annotation.IntDef; 31b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 32b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banesimport android.support.v4.view.ViewCompat; 33058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyarimport android.support.v7.appcompat.R; 34058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 3593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport java.lang.annotation.Retention; 3693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banesimport java.lang.annotation.RetentionPolicy; 3793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 38058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar/** 3993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * A drawable that can draw a "Drawer hamburger" menu or an arrow and animate between them. 4093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * <p> 4193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * The progress between the two states is controlled via {@link #setProgress(float)}. 4293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * </p> 43058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 4493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banespublic class DrawerArrowDrawable extends Drawable { 4593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 4693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 47b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point towards the left. 4893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * 4993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #setDirection(int) 5093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #getDirection() 5193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 5293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public static final int ARROW_DIRECTION_LEFT = 0; 5393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 5493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 55b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point towards the right. 5693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * 5793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #setDirection(int) 5893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * @see #getDirection() 5993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 6093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public static final int ARROW_DIRECTION_RIGHT = 1; 6193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 62b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes /** 63b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point towards the start. 64b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 65b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * <p>When used in a view with a {@link ViewCompat#LAYOUT_DIRECTION_RTL RTL} layout direction, 66b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * this is the same as {@link #ARROW_DIRECTION_RIGHT}, otherwise it is the same as 67b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * {@link #ARROW_DIRECTION_LEFT}.</p> 68b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 69b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #setDirection(int) 70b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #getDirection() 71b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes */ 72b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes public static final int ARROW_DIRECTION_START = 2; 73b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 74b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes /** 75b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * Direction to make the arrow point to the end. 76b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 77b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * <p>When used in a view with a {@link ViewCompat#LAYOUT_DIRECTION_RTL RTL} layout direction, 78b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * this is the same as {@link #ARROW_DIRECTION_LEFT}, otherwise it is the same as 79b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * {@link #ARROW_DIRECTION_RIGHT}.</p> 80b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * 81b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #setDirection(int) 82b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes * @see #getDirection() 83b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes */ 84b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes public static final int ARROW_DIRECTION_END = 3; 85b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 8693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** @hide */ 87b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes @IntDef({ARROW_DIRECTION_LEFT, ARROW_DIRECTION_RIGHT, 88b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes ARROW_DIRECTION_START, ARROW_DIRECTION_END}) 8993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes @Retention(RetentionPolicy.SOURCE) 9093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public @interface ArrowDirection {} 91058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 92058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private final Paint mPaint = new Paint(); 93058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 94058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The angle in degress that the arrow head is inclined at. 95058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private static final float ARROW_HEAD_ANGLE = (float) Math.toRadians(45); 96058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The length of top and bottom bars when they merge into an arrow 97fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mArrowHeadLength; 98058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The length of middle bar 99fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mBarLength; 100058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The length of the middle bar when arrow is shaped 101fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mArrowShaftLength; 102058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The space between bars when they are parallel 103fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private float mBarGap; 104058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Whether bars should spin or not during progress 105fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes private boolean mSpin; 106058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Use Path instead of canvas operations so that if color has transparency, overlapping sections 107058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // wont look different 108058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private final Path mPath = new Path(); 109058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The reported intrinsic size of the drawable. 110058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private final int mSize; 111058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Whether we should mirror animation when animation is reversed. 112058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private boolean mVerticalMirror = false; 113058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The interpolated version of the original progress 114058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private float mProgress; 1159ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // the amount that overlaps w/ bar size when rotation is max 1169ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar private float mMaxCutForBarSize; 11793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes // The arrow direction 118b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes private int mDirection = ARROW_DIRECTION_START; 119058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 120058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar /** 121058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * @param context used to get the configuration for the drawable from 122058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 12393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public DrawerArrowDrawable(Context context) { 124fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStyle(Paint.Style.STROKE); 125fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStrokeJoin(Paint.Join.MITER); 126fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStrokeCap(Paint.Cap.BUTT); 127058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPaint.setAntiAlias(true); 128fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 129fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final TypedArray a = context.getTheme().obtainStyledAttributes(null, 130fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes R.styleable.DrawerArrowToggle, R.attr.drawerArrowStyle, 131fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes R.style.Base_Widget_AppCompat_DrawerArrowToggle); 132fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 133fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setColor(a.getColor(R.styleable.DrawerArrowToggle_color, 0)); 134fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setBarThickness(a.getDimension(R.styleable.DrawerArrowToggle_thickness, 0)); 135fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setSpinEnabled(a.getBoolean(R.styleable.DrawerArrowToggle_spinBars, true)); 1369ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // round this because having this floating may cause bad measurements 137fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes setGapSize(Math.round(a.getDimension(R.styleable.DrawerArrowToggle_gapBetweenBars, 0))); 138fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 139fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mSize = a.getDimensionPixelSize(R.styleable.DrawerArrowToggle_drawableSize, 0); 1409ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // round this because having this floating may cause bad measurements 141fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mBarLength = Math.round(a.getDimension(R.styleable.DrawerArrowToggle_barLength, 0)); 1429ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // round this because having this floating may cause bad measurements 143fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowHeadLength = Math.round(a.getDimension( 144fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes R.styleable.DrawerArrowToggle_arrowHeadLength, 0)); 145fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowShaftLength = a.getDimension(R.styleable.DrawerArrowToggle_arrowShaftLength, 0); 14693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes a.recycle(); 147fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 148058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 149fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 150fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the length of the arrow head (from tip to edge, perpendicular to the shaft). 151fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 152fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param length the length in pixels 153fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 154fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setArrowHeadLength(float length) { 155fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mArrowHeadLength != length) { 156fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowHeadLength = length; 157fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 158fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 159fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 160fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 161fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 162fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the length of the arrow head (from tip to edge, perpendicular to the shaft), 163fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * in pixels. 164fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 165fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getArrowHeadLength() { 166fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mArrowHeadLength; 167fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 168fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 169fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 170fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the arrow shaft length. 171fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 172fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param length the length in pixels 173fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 174fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setArrowShaftLength(float length) { 175fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mArrowShaftLength != length) { 176fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mArrowShaftLength = length; 177fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 178fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 179fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 180fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 181fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 182fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the arrow shaft length in pixels. 183fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 184fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getArrowShaftLength() { 185fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mArrowShaftLength; 186fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 187fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 188fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 189fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * The length of the bars when they are parallel to each other. 190fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 191fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getBarLength() { 192fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mBarLength; 193fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 194fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 195fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 196fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the length of the bars when they are parallel to each other. 197fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 198fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param length the length in pixels 199fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 200fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setBarLength(float length) { 201fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mBarLength != length) { 202fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mBarLength = length; 203fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 204fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 205fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 206fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 207fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 208fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the color of the drawable. 209fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 210fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setColor(@ColorInt int color) { 211fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (color != mPaint.getColor()) { 212fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setColor(color); 213fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 214fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 215fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 216fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 217fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 218fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the color of the drawable. 219fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 220fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes @ColorInt 221fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public int getColor() { 222fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mPaint.getColor(); 223fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 224fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 225fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 226fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the thickness (stroke size) for the bars. 227fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 228fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param width stroke width in pixels 229fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 230fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setBarThickness(float width) { 231fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mPaint.getStrokeWidth() != width) { 232fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPaint.setStrokeWidth(width); 233fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mMaxCutForBarSize = (float) (width / 2 * Math.cos(ARROW_HEAD_ANGLE)); 234fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 235fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 236fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 237fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 238fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 239fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the thickness (stroke width) of the bars. 240fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 241fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getBarThickness() { 242fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mPaint.getStrokeWidth(); 243fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 244fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 245fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 246fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns the max gap between the bars when they are parallel to each other. 247fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 248fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #getGapSize() 249fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 250fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public float getGapSize() { 251fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mBarGap; 252fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 2539ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar 254fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 255fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Sets the max gap between the bars when they are parallel to each other. 256fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 257fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param gap the gap in pixels 258fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 259fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #getGapSize() 260fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 261fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setGapSize(float gap) { 262fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (gap != mBarGap) { 263fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mBarGap = gap; 264fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 265fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 266058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 267058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 26893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 26993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Set the arrow direction. 27093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 27193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setDirection(@ArrowDirection int direction) { 27293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes if (direction != mDirection) { 27393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes mDirection = direction; 27493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes invalidateSelf(); 27593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 27693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 27793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 27893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 279fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns whether the bars should rotate or not during the transition. 280fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 281fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #setSpinEnabled(boolean) 282fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 283fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public boolean isSpinEnabled() { 284fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes return mSpin; 285fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 286fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 287fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 288fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * Returns whether the bars should rotate or not during the transition. 289fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 290fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @param enabled true if the bars should rotate. 291fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * 292fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes * @see #isSpinEnabled() 293fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes */ 294fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes public void setSpinEnabled(boolean enabled) { 295fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes if (mSpin != enabled) { 296fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mSpin = enabled; 297fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes invalidateSelf(); 298fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 299fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes } 300fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 301fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes /** 30293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Returns the arrow direction. 30393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 30493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes @ArrowDirection 30593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public int getDirection() { 30693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes return mDirection; 30793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 308058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 309058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar /** 310058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * If set, canvas is flipped when progress reached to end and going back to start. 311058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 31293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setVerticalMirror(boolean verticalMirror) { 31393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes if (mVerticalMirror != verticalMirror) { 31493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes mVerticalMirror = verticalMirror; 31593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes invalidateSelf(); 31693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } 317058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 318058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 319058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 320058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public void draw(Canvas canvas) { 321058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar Rect bounds = getBounds(); 322b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 323b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes final boolean flipToPointRight; 324b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes switch (mDirection) { 325b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_LEFT: 326b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = false; 327b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 328b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_RIGHT: 329b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = true; 330b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 331b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_END: 332b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = DrawableCompat.getLayoutDirection(this) 333b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes == ViewCompat.LAYOUT_DIRECTION_LTR; 334b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 335b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes case ARROW_DIRECTION_START: 336b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes default: 337b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes flipToPointRight = DrawableCompat.getLayoutDirection(this) 338b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes == ViewCompat.LAYOUT_DIRECTION_RTL; 339b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes break; 340b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes } 341b01b01dddd64c945dd8dfa896648aa36dc47dde3Chris Banes 342058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Interpolated widths of arrow bars 343fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 344fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes float arrowHeadBarLength = (float) Math.sqrt(mArrowHeadLength * mArrowHeadLength * 2); 345fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes arrowHeadBarLength = lerp(mBarLength, arrowHeadBarLength, mProgress); 346fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowShaftLength = lerp(mBarLength, mArrowShaftLength, mProgress); 347058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Interpolated size of middle bar 348fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowShaftCut = Math.round(lerp(0, mMaxCutForBarSize, mProgress)); 349058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The rotation of the top and bottom bars (that make the arrow head) 350058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar final float rotation = lerp(0, ARROW_HEAD_ANGLE, mProgress); 351058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 352058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // The whole canvas rotates as the transition happens 35393011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes final float canvasRotate = lerp(flipToPointRight ? 0 : -180, 35493011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes flipToPointRight ? 180 : 0, mProgress); 35593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes 356fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowWidth = Math.round(arrowHeadBarLength * Math.cos(rotation)); 357fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowHeight = Math.round(arrowHeadBarLength * Math.sin(rotation)); 3589ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar 359058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.rewind(); 360fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float topBottomBarOffset = lerp(mBarGap + mPaint.getStrokeWidth(), -mMaxCutForBarSize, 3619ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar mProgress); 362058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 363fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float arrowEdge = -arrowShaftLength / 2; 364058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // draw middle bar 365fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPath.moveTo(arrowEdge + arrowShaftCut, 0); 366fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes mPath.rLineTo(arrowShaftLength - arrowShaftCut * 2, 0); 367058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 3689ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // bottom bar 369058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.moveTo(arrowEdge, topBottomBarOffset); 370058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.rLineTo(arrowWidth, arrowHeight); 371058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 3729ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar // top bar 373058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.moveTo(arrowEdge, -topBottomBarOffset); 374058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.rLineTo(arrowWidth, -arrowHeight); 3759ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar 376058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPath.close(); 377058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 378058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar canvas.save(); 379fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 380058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // Rotate the whole canvas if spinning, if not, rotate it 180 to get 381058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar // the arrow pointing the other way for RTL. 382fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final float barThickness = mPaint.getStrokeWidth(); 383fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes final int remainingSpace = (int) (bounds.height() - barThickness * 3 - mBarGap * 2); 384fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes float yOffset = (remainingSpace / 4) * 2; // making sure it is a multiple of 2. 385fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes yOffset += barThickness * 1.5 + mBarGap; 386fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes 387fab671ee55f26d6f3c9381a3e6d444d23dd970d2Chris Banes canvas.translate(bounds.centerX(), yOffset); 388058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar if (mSpin) { 38993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes canvas.rotate(canvasRotate * ((mVerticalMirror ^ flipToPointRight) ? -1 : 1)); 39093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes } else if (flipToPointRight) { 3919ce2474543a32abfba8a0bdf65133416c5ba7a34Yigit Boyar canvas.rotate(180); 392058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 393058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar canvas.drawPath(mPath, mPaint); 394058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 395058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar canvas.restore(); 396058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 397058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 398058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 39993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setAlpha(int alpha) { 400486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes if (alpha != mPaint.getAlpha()) { 401486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes mPaint.setAlpha(alpha); 402486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes invalidateSelf(); 403486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes } 404058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 405058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 406058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 407058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public void setColorFilter(ColorFilter colorFilter) { 408058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar mPaint.setColorFilter(colorFilter); 409486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes invalidateSelf(); 410058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 411058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 412058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 413058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public int getIntrinsicHeight() { 414058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return mSize; 415058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 416058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 417058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 418058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public int getIntrinsicWidth() { 419058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return mSize; 420058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 421058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 422058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar @Override 423058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public int getOpacity() { 424058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return PixelFormat.TRANSLUCENT; 425058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 426058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 42793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 42893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Returns the current progress of the arrow. 42993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 43093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes @FloatRange(from = 0.0, to = 1.0) 431058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar public float getProgress() { 432058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return mProgress; 433058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 434058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 43593011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes /** 43693011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * Set the progress of the arrow. 43793011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * 43893011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * <p>A value of {@code 0.0} indicates that the arrow should be drawn in it's starting 43993011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * position. A value of {@code 1.0} indicates that the arrow should be drawn in it's ending 44093011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes * position.</p> 44193011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes */ 44293011d6b0ca0622a6b098d3c3670ac7cc7bf9632Chris Banes public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { 443486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes if (mProgress != progress) { 444486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes mProgress = progress; 445486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes invalidateSelf(); 446486ecff84a98c7b397e4a19c85a87f565d09f197Chris Banes } 447058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 448058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar 449058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar /** 450403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes * Returns the paint instance used for all drawing. 451403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes */ 452403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes public final Paint getPaint() { 453403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes return mPaint; 454403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes } 455403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes 456403b20a282fa3d71b799bde1b4699eb8aade0c83Chris Banes /** 457058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar * Linear interpolate between a and b with parameter t. 458058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar */ 459058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar private static float lerp(float a, float b, float t) { 460058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar return a + (b - a) * t; 461058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar } 462058467cbd6dd0acdfaec61e65ab9e352868ec5c9Yigit Boyar}