AppCompatSeekBarHelper.java revision 3de8a4e8305507475d7890205184946a25cf45e7
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.appcompat.widget;
18
19import android.content.res.ColorStateList;
20import android.graphics.Canvas;
21import android.graphics.PorterDuff;
22import android.graphics.drawable.Drawable;
23import android.util.AttributeSet;
24import android.widget.SeekBar;
25
26import androidx.annotation.Nullable;
27import androidx.annotation.RequiresApi;
28import androidx.appcompat.R;
29import androidx.core.graphics.drawable.DrawableCompat;
30import androidx.core.view.ViewCompat;
31
32class AppCompatSeekBarHelper extends AppCompatProgressBarHelper {
33
34    private final SeekBar mView;
35
36    private Drawable mTickMark;
37    private ColorStateList mTickMarkTintList = null;
38    private PorterDuff.Mode mTickMarkTintMode = null;
39    private boolean mHasTickMarkTint = false;
40    private boolean mHasTickMarkTintMode = false;
41
42    AppCompatSeekBarHelper(SeekBar view) {
43        super(view);
44        mView = view;
45    }
46
47    @Override
48    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
49        super.loadFromAttributes(attrs, defStyleAttr);
50
51        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
52                R.styleable.AppCompatSeekBar, defStyleAttr, 0);
53        final Drawable drawable = a.getDrawableIfKnown(R.styleable.AppCompatSeekBar_android_thumb);
54        if (drawable != null) {
55            mView.setThumb(drawable);
56        }
57
58        final Drawable tickMark = a.getDrawable(R.styleable.AppCompatSeekBar_tickMark);
59        setTickMark(tickMark);
60
61        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTintMode)) {
62            mTickMarkTintMode = DrawableUtils.parseTintMode(a.getInt(
63                    R.styleable.AppCompatSeekBar_tickMarkTintMode, -1), mTickMarkTintMode);
64            mHasTickMarkTintMode = true;
65        }
66
67        if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTint)) {
68            mTickMarkTintList = a.getColorStateList(R.styleable.AppCompatSeekBar_tickMarkTint);
69            mHasTickMarkTint = true;
70        }
71
72        a.recycle();
73
74        applyTickMarkTint();
75    }
76
77    void setTickMark(@Nullable Drawable tickMark) {
78        if (mTickMark != null) {
79            mTickMark.setCallback(null);
80        }
81
82        mTickMark = tickMark;
83
84        if (tickMark != null) {
85            tickMark.setCallback(mView);
86            DrawableCompat.setLayoutDirection(tickMark, ViewCompat.getLayoutDirection(mView));
87            if (tickMark.isStateful()) {
88                tickMark.setState(mView.getDrawableState());
89            }
90            applyTickMarkTint();
91        }
92
93        mView.invalidate();
94    }
95
96    @Nullable
97    Drawable getTickMark() {
98        return mTickMark;
99    }
100
101    void setTickMarkTintList(@Nullable ColorStateList tint) {
102        mTickMarkTintList = tint;
103        mHasTickMarkTint = true;
104
105        applyTickMarkTint();
106    }
107
108    @Nullable
109    ColorStateList getTickMarkTintList() {
110        return mTickMarkTintList;
111    }
112
113    void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
114        mTickMarkTintMode = tintMode;
115        mHasTickMarkTintMode = true;
116
117        applyTickMarkTint();
118    }
119
120    @Nullable
121    PorterDuff.Mode getTickMarkTintMode() {
122        return mTickMarkTintMode;
123    }
124
125    private void applyTickMarkTint() {
126        if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) {
127            mTickMark = DrawableCompat.wrap(mTickMark.mutate());
128
129            if (mHasTickMarkTint) {
130                DrawableCompat.setTintList(mTickMark, mTickMarkTintList);
131            }
132
133            if (mHasTickMarkTintMode) {
134                DrawableCompat.setTintMode(mTickMark, mTickMarkTintMode);
135            }
136
137            // The drawable (or one of its children) may not have been
138            // stateful before applying the tint, so let's try again.
139            if (mTickMark.isStateful()) {
140                mTickMark.setState(mView.getDrawableState());
141            }
142        }
143    }
144
145    @RequiresApi(11)
146    void jumpDrawablesToCurrentState() {
147        if (mTickMark != null) {
148            mTickMark.jumpToCurrentState();
149        }
150    }
151
152    void drawableStateChanged() {
153        final Drawable tickMark = mTickMark;
154        if (tickMark != null && tickMark.isStateful()
155                && tickMark.setState(mView.getDrawableState())) {
156            mView.invalidateDrawable(tickMark);
157        }
158    }
159
160    /**
161     * Draw the tick marks.
162     */
163    void drawTickMarks(Canvas canvas) {
164        if (mTickMark != null) {
165            final int count = mView.getMax();
166            if (count > 1) {
167                final int w = mTickMark.getIntrinsicWidth();
168                final int h = mTickMark.getIntrinsicHeight();
169                final int halfW = w >= 0 ? w / 2 : 1;
170                final int halfH = h >= 0 ? h / 2 : 1;
171                mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
172
173                final float spacing = (mView.getWidth() - mView.getPaddingLeft()
174                        - mView.getPaddingRight()) / (float) count;
175                final int saveCount = canvas.save();
176                canvas.translate(mView.getPaddingLeft(), mView.getHeight() / 2);
177                for (int i = 0; i <= count; i++) {
178                    mTickMark.draw(canvas);
179                    canvas.translate(spacing, 0);
180                }
181                canvas.restoreToCount(saveCount);
182            }
183        }
184    }
185
186}
187