[go: nahoru, domu]

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}