AppCompatSeekBarHelper.java revision 3de8a4e8305507475d7890205184946a25cf45e7
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; 27ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RequiresApi; 283de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.appcompat.R; 29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.graphics.drawable.DrawableCompat; 30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewCompat; 3110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 3210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banesclass AppCompatSeekBarHelper extends AppCompatProgressBarHelper { 3310e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 3410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes private final SeekBar mView; 3510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 36b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private Drawable mTickMark; 37b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private ColorStateList mTickMarkTintList = null; 38b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private PorterDuff.Mode mTickMarkTintMode = null; 39b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private boolean mHasTickMarkTint = false; 40b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private boolean mHasTickMarkTintMode = false; 41b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 424c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes AppCompatSeekBarHelper(SeekBar view) { 434c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes super(view); 4410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes mView = view; 4510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes } 4610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 47dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 4810e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { 4910e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes super.loadFromAttributes(attrs, defStyleAttr); 5010e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes 5110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs, 52b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes R.styleable.AppCompatSeekBar, defStyleAttr, 0); 53b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final Drawable drawable = a.getDrawableIfKnown(R.styleable.AppCompatSeekBar_android_thumb); 5410e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes if (drawable != null) { 5510e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes mView.setThumb(drawable); 5610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes } 57b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 58b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final Drawable tickMark = a.getDrawable(R.styleable.AppCompatSeekBar_tickMark); 59b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes setTickMark(tickMark); 60b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 61b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTintMode)) { 62b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintMode = DrawableUtils.parseTintMode(a.getInt( 63b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes R.styleable.AppCompatSeekBar_tickMarkTintMode, -1), mTickMarkTintMode); 64b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTintMode = true; 65b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 66b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 67b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (a.hasValue(R.styleable.AppCompatSeekBar_tickMarkTint)) { 68b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintList = a.getColorStateList(R.styleable.AppCompatSeekBar_tickMarkTint); 69b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTint = true; 70b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 71b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 7210e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes a.recycle(); 73b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 74b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 75b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 76b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 77b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void setTickMark(@Nullable Drawable tickMark) { 78b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null) { 79b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.setCallback(null); 80b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 81b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 82b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark = tickMark; 83b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 84b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (tickMark != null) { 85b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes tickMark.setCallback(mView); 86b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes DrawableCompat.setLayoutDirection(tickMark, ViewCompat.getLayoutDirection(mView)); 87b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (tickMark.isStateful()) { 88b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes tickMark.setState(mView.getDrawableState()); 89b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 90b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 91b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 92b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 93b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mView.invalidate(); 94b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 95b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 96b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes @Nullable 97b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes Drawable getTickMark() { 98b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes return mTickMark; 99b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 100b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 101b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void setTickMarkTintList(@Nullable ColorStateList tint) { 102b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintList = tint; 103b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTint = true; 104b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 105b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 106b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 107b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 108b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes @Nullable 109b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes ColorStateList getTickMarkTintList() { 110b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes return mTickMarkTintList; 11110e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes } 112b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 113b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) { 114b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMarkTintMode = tintMode; 115b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mHasTickMarkTintMode = true; 116b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 117b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes applyTickMarkTint(); 118b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 119b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 120b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes @Nullable 121b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes PorterDuff.Mode getTickMarkTintMode() { 122b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes return mTickMarkTintMode; 123b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 124b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 125b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes private void applyTickMarkTint() { 126b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) { 127168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes mTickMark = DrawableCompat.wrap(mTickMark.mutate()); 128b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 129b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mHasTickMarkTint) { 130168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes DrawableCompat.setTintList(mTickMark, mTickMarkTintList); 131b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 132b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 133b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mHasTickMarkTintMode) { 134168fbe2c9b213338bce447c8825303c86b5b9281Chris Banes DrawableCompat.setTintMode(mTickMark, mTickMarkTintMode); 135b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 136b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 137b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes // The drawable (or one of its children) may not have been 138b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes // stateful before applying the tint, so let's try again. 139b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark.isStateful()) { 140b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.setState(mView.getDrawableState()); 141b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 142b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 143b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 144b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 1458f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette @RequiresApi(11) 146b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void jumpDrawablesToCurrentState() { 147b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null) { 148b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.jumpToCurrentState(); 149b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 150b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 151b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 152b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void drawableStateChanged() { 153b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final Drawable tickMark = mTickMark; 154b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (tickMark != null && tickMark.isStateful() 155b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes && tickMark.setState(mView.getDrawableState())) { 156b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mView.invalidateDrawable(tickMark); 157b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 158b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 159b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 160b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes /** 161b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes * Draw the tick marks. 162b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes */ 163b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes void drawTickMarks(Canvas canvas) { 164b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (mTickMark != null) { 165b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int count = mView.getMax(); 166b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes if (count > 1) { 167b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int w = mTickMark.getIntrinsicWidth(); 168b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int h = mTickMark.getIntrinsicHeight(); 169b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int halfW = w >= 0 ? w / 2 : 1; 170b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int halfH = h >= 0 ? h / 2 : 1; 171b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.setBounds(-halfW, -halfH, halfW, halfH); 172b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 173b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final float spacing = (mView.getWidth() - mView.getPaddingLeft() 174b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes - mView.getPaddingRight()) / (float) count; 175b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes final int saveCount = canvas.save(); 176b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes canvas.translate(mView.getPaddingLeft(), mView.getHeight() / 2); 177b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes for (int i = 0; i <= count; i++) { 178b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes mTickMark.draw(canvas); 179b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes canvas.translate(spacing, 0); 180b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 181b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes canvas.restoreToCount(saveCount); 182b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 183b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 184b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes } 185b19cba1c83a68efb5c18ef74e4e5d376fa166625Chris Banes 18610e2dbc1ad1c01d2824d921a8b0f070859d6f146Chris Banes} 187