| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.support.v7.internal.widget; |
| |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapShader; |
| import android.graphics.Shader; |
| import android.graphics.drawable.AnimationDrawable; |
| import android.graphics.drawable.BitmapDrawable; |
| import android.graphics.drawable.ClipDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.graphics.drawable.LayerDrawable; |
| import android.graphics.drawable.ShapeDrawable; |
| import android.graphics.drawable.shapes.RoundRectShape; |
| import android.graphics.drawable.shapes.Shape; |
| import android.support.v4.graphics.drawable.DrawableWrapper; |
| import android.support.v4.view.ViewCompat; |
| import android.util.AttributeSet; |
| import android.view.Gravity; |
| import android.widget.RatingBar; |
| |
| /** |
| * An tint aware {@link android.widget.RatingBar}. |
| * <p> |
| * This will automatically be used when you use {@link android.widget.RatingBar} in your |
| * layouts. You should only need to manually use this class when writing custom views. |
| */ |
| public class TintRatingBar extends RatingBar { |
| |
| private static final int[] TINT_ATTRS = { |
| android.R.attr.indeterminateDrawable, |
| android.R.attr.progressDrawable |
| }; |
| |
| private Bitmap mSampleTile; |
| |
| public TintRatingBar(Context context) { |
| this(context, null); |
| } |
| |
| public TintRatingBar(Context context, AttributeSet attrs) { |
| this(context, attrs, android.R.attr.ratingBarStyle); |
| } |
| |
| public TintRatingBar(Context context, AttributeSet attrs, int defStyleAttr) { |
| super(context, attrs, defStyleAttr); |
| |
| if (TintManager.SHOULD_BE_USED) { |
| TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs, |
| TINT_ATTRS, defStyleAttr, 0); |
| |
| Drawable drawable = a.getDrawable(0); |
| if (drawable != null) { |
| setIndeterminateDrawable(tileifyIndeterminate(drawable)); |
| } |
| |
| drawable = a.getDrawable(1); |
| if (drawable != null) { |
| setProgressDrawable(tileify(drawable, false)); |
| } |
| |
| a.recycle(); |
| } |
| } |
| |
| /** |
| * Converts a drawable to a tiled version of itself. It will recursively |
| * traverse layer and state list drawables. |
| */ |
| private Drawable tileify(Drawable drawable, boolean clip) { |
| if (drawable instanceof DrawableWrapper) { |
| Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable(); |
| if (inner != null) { |
| inner = tileify(inner, clip); |
| ((DrawableWrapper) drawable).setWrappedDrawable(inner); |
| } |
| } else if (drawable instanceof LayerDrawable) { |
| LayerDrawable background = (LayerDrawable) drawable; |
| final int N = background.getNumberOfLayers(); |
| Drawable[] outDrawables = new Drawable[N]; |
| |
| for (int i = 0; i < N; i++) { |
| int id = background.getId(i); |
| outDrawables[i] = tileify(background.getDrawable(i), |
| (id == android.R.id.progress || id == android.R.id.secondaryProgress)); |
| } |
| LayerDrawable newBg = new LayerDrawable(outDrawables); |
| |
| for (int i = 0; i < N; i++) { |
| newBg.setId(i, background.getId(i)); |
| } |
| |
| return newBg; |
| |
| } else if (drawable instanceof BitmapDrawable) { |
| final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap(); |
| if (mSampleTile == null) { |
| mSampleTile = tileBitmap; |
| } |
| |
| final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape()); |
| final BitmapShader bitmapShader = new BitmapShader(tileBitmap, |
| Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); |
| shapeDrawable.getPaint().setShader(bitmapShader); |
| return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT, |
| ClipDrawable.HORIZONTAL) : shapeDrawable; |
| } |
| |
| return drawable; |
| } |
| |
| /** |
| * Convert a AnimationDrawable for use as a barberpole animation. |
| * Each frame of the animation is wrapped in a ClipDrawable and |
| * given a tiling BitmapShader. |
| */ |
| private Drawable tileifyIndeterminate(Drawable drawable) { |
| if (drawable instanceof AnimationDrawable) { |
| AnimationDrawable background = (AnimationDrawable) drawable; |
| final int N = background.getNumberOfFrames(); |
| AnimationDrawable newBg = new AnimationDrawable(); |
| newBg.setOneShot(background.isOneShot()); |
| |
| for (int i = 0; i < N; i++) { |
| Drawable frame = tileify(background.getFrame(i), true); |
| frame.setLevel(10000); |
| newBg.addFrame(frame, background.getDuration(i)); |
| } |
| newBg.setLevel(10000); |
| drawable = newBg; |
| } |
| return drawable; |
| } |
| |
| private Shape getDrawableShape() { |
| final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 }; |
| return new RoundRectShape(roundedCorners, null, null); |
| } |
| |
| @Override |
| protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
| |
| if (mSampleTile != null) { |
| final int width = mSampleTile.getWidth() * getNumStars(); |
| setMeasuredDimension(ViewCompat.resolveSizeAndState(width, widthMeasureSpec, 0), |
| getMeasuredHeight()); |
| } |
| } |
| |
| } |