110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes/* 210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Copyright (C) 2015 The Android Open Source Project 310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * 410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * you may not use this file except in compliance with the License. 610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * You may obtain a copy of the License at 710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * 810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * 1010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * Unless required by applicable law or agreed to in writing, software 1110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 1210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * See the License for the specific language governing permissions and 1410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes * limitations under the License. 1510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes */ 1610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.appcompat.widget; 1810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 19b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.content.res.ColorStateList; 20b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.graphics.Canvas; 21b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banesimport android.graphics.PorterDuff; 2210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesimport android.graphics.drawable.Drawable; 233de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport android.util.AttributeSet; 243de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport android.widget.SeekBar; 253de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikas 26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable; 273de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.appcompat.R; 28ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.graphics.drawable.DrawableCompat; 29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewCompat; 3010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 3110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesclass AppCompatSeekBarHelper extends AppCompatProgressBarHelper { 3210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 3310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes private final SeekBar mView; 3410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 35b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private Drawable mTickMark; 36b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private ColorStateList mTickMarkTintList = null; 37b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private PorterDuff.Mode mTickMarkTintMode = null; 38b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private boolean mHasTickMarkTint = false; 39b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private boolean mHasTickMarkTintMode = false; 40b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 414c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes AppCompatSeekBarHelper(SeekBar view) { 424c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes super(view); 4310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes mView = view; 4410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes } 4510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 46dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 4710e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { 4810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes super.loadFromAttributes(attrs, defStyleAttr); 4910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 5010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs, 51b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes R.styleable.AppCompatSeekBar, defStyleAttr, 0); 52b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final Drawable drawable = a.getDrawableIfKnown(R.styleable.AppCompatSeekBar_android_thumb); 5310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes if (drawable != null) { 5410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes mView.setThumb(drawable); 5510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes } 56b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 57b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final Drawable tickMark = a.getDrawable(R.styleable.AppCompatSeekBar_tickMark); 58b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes setTickMark(tickMark); 59b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 60b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTintMode)) { 61b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintMode = DrawableUtils.parseTintMode(a.getInt( 62b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes R.styleable.AppCompatSeekBar_tickMarkTintMode, -1), mTickMarkTintMode); 63b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTintMode = true; 64b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 65b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 66b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTint)) { 67b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintList = a.getColorStateList(R.styleable.AppCompatSeekBar_tickMarkTint); 68b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTint = true; 69b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 70b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 7110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes a.recycle(); 72b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 73b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 74b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 75b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 76b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void setTickMark(@Nullable Drawable tickMark) { 77b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null) { 78b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.setCallback(null); 79b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 80b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 81b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark = tickMark; 82b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 83b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (tickMark != null) { 84b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes tickMark.setCallback(mView); 85b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes DrawableCompat.setLayoutDirection(tickMark, ViewCompat.getLayoutDirection(mView)); 86b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (tickMark.isStateful()) { 87b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes tickMark.setState(mView.getDrawableState()); 88b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 89b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 90b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 91b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 92b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mView.invalidate(); 93b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 94b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 95b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes @Nullable 96b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes Drawable getTickMark() { 97b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes return mTickMark; 98b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 99b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 100b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void setTickMarkTintList(@Nullable ColorStateList tint) { 101b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintList = tint; 102b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTint = true; 103b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 104b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 105b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 106b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 107b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes @Nullable 108b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes ColorStateList getTickMarkTintList() { 109b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes return mTickMarkTintList; 11010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes } 111b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 112b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) { 113b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintMode = tintMode; 114b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTintMode = true; 115b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 116b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 117b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 118b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 119b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes @Nullable 120b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes PorterDuff.Mode getTickMarkTintMode() { 121b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes return mTickMarkTintMode; 122b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 123b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 124b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private void applyTickMarkTint() { 125b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) { 126168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes mTickMark = DrawableCompat.wrap(mTickMark.mutate()); 127b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 128b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mHasTickMarkTint) { 129168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes DrawableCompat.setTintList(mTickMark, mTickMarkTintList); 130b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 131b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 132b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mHasTickMarkTintMode) { 133168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes DrawableCompat.setTintMode(mTickMark, mTickMarkTintMode); 134b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 135b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 136b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes // The drawable (or one of its children) may not have been 137b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes // stateful before applying the tint, so let's try again. 138b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark.isStateful()) { 139b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.setState(mView.getDrawableState()); 140b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 141b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 142b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 143b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 144b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void jumpDrawablesToCurrentState() { 145b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null) { 146b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.jumpToCurrentState(); 147b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 148b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 149b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 150b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void drawableStateChanged() { 151b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final Drawable tickMark = mTickMark; 152b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (tickMark != null && tickMark.isStateful() 153b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes && tickMark.setState(mView.getDrawableState())) { 154b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mView.invalidateDrawable(tickMark); 155b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 156b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 157b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 158b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes /** 159b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes * Draw the tick marks. 160b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes */ 161b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void drawTickMarks(Canvas canvas) { 162b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null) { 163b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int count = mView.getMax(); 164b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (count > 1) { 165b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int w = mTickMark.getIntrinsicWidth(); 166b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int h = mTickMark.getIntrinsicHeight(); 167b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int halfW = w >= 0 ? w / 2 : 1; 168b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int halfH = h >= 0 ? h / 2 : 1; 169b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.setBounds(-halfW, -halfH, halfW, halfH); 170b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 171b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final float spacing = (mView.getWidth() - mView.getPaddingLeft() 172b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes - mView.getPaddingRight()) / (float) count; 173b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int saveCount = canvas.save(); 174b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes canvas.translate(mView.getPaddingLeft(), mView.getHeight() / 2); 175b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes for (int i = 0; i <= count; i++) { 176b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.draw(canvas); 177b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes canvas.translate(spacing, 0); 178b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 179b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes canvas.restoreToCount(saveCount); 180b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 181b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 182b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 183b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 18410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes} 185