ShapeDrawable как progressDrawable для RatingBar в Android?
Кажется, я не могу установить ShapeDrawable как progressDrawable для Ratingbar. Я попробовал следующее, но не получилось:
<RatingBar
android:id="@+id/ratingbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:numStars="5"
android:stepSize="1.0"
android:rating="3.0"
style="@style/myRatingBar"
/>
Стиль myRatingbar:
<style name="myRatingBar" parent="@android:style/Widget.RatingBar">
<item name="android:progressDrawable">@drawable/ratingbar_full</item>
<item name="android:indeterminateDrawable">@drawable/ratingbar_full</item>
<item name="android:minHeight">48dip</item>
<item name="android:maxHeight">48dip</item>
<item name="android:scaleType">center</item>
</style>
ratingbar_full.xml:
<shape
android:shape="ring"
android:innerRadius="10dip"
android:thickness="1dip">
<solid android:color="@color/red" />
<size
android:width="48dip"
android:height="48dip"
/>
</shape>
Ничто не показывает на экране.
РЕДАКТИРОВАТЬ: использовать.png вместо формы работает для этой линии:
@ Вытяжка /ratingbar_full
4 ответа
Я настроил метод @ChrisJenkins, чтобы вы могли устанавливать размер значков RatingBar и настраиваемые цвета оттенков для рейтинговых изображений. Вы можете установить отступы на вашем RatingBar или установить свою ширину и высоту. Решение @ChrisJenkins мне очень помогло, наконец, создать полностью настраиваемый RatingBar. Вы также можете установить параметры в своем XML.
public class DrawableRatingBar extends RatingBar
{
// TileBitmap to base the width and hight off of.
@Nullable
private Bitmap iconTile;
private float scaleIconFactor;
private @ColorInt int iconBackgroundColor;
private @ColorInt int iconForegroundColor;
private @DrawableRes int iconDrawable;
public DrawableRatingBar(Context context)
{
super(context);
init();
}
public DrawableRatingBar(Context context, AttributeSet attrs)
{
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DrawableRatingBarItem);
scaleIconFactor = a.getFloat(R.styleable.DrawableRatingBarItem_scaleIconFactor, 1);
iconBackgroundColor = a.getColor(R.styleable.DrawableRatingBarItem_iconBackgroundColor, Color.BLACK);
iconForegroundColor = a.getColor(R.styleable.DrawableRatingBarItem_iconForegroundColor, Color.WHITE);
iconDrawable = a.getResourceId(R.styleable.DrawableRatingBarItem_iconDrawable, -1);
a.recycle();
init();
}
public DrawableRatingBar(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DrawableRatingBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init()
{
setProgressDrawable(createProgressDrawable());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (iconTile != null)
{
final int width = iconTile.getWidth() * getNumStars();
final int height = iconTile.getHeight();
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
resolveSizeAndState(height, heightMeasureSpec, 0));
}
}
protected LayerDrawable createProgressDrawable()
{
final Drawable backgroundDrawable = createBackgroundDrawableShape();
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] {backgroundDrawable,
backgroundDrawable,
createProgressDrawableShape()});
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.secondaryProgress);
layerDrawable.setId(2, android.R.id.progress);
return layerDrawable;
}
protected Drawable createBackgroundDrawableShape()
{
Drawable drawable = ContextCompat.getDrawable(getContext(), iconDrawable);
final Bitmap tileBitmap = scaleImageWithColor(drawable, scaleIconFactor, iconBackgroundColor);
if (iconTile == null)
{
iconTile = tileBitmap;
}
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
return shapeDrawable;
}
private void setRatingStarColor(Drawable drawable, @ColorInt int color)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
DrawableCompat.setTint(drawable, color);
}
else
{
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
}
protected Drawable createProgressDrawableShape()
{
Drawable drawable = ContextCompat.getDrawable(getContext(), iconDrawable);
final Bitmap tileBitmap = scaleImageWithColor(drawable, scaleIconFactor, iconForegroundColor);
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
return new ClipDrawable(shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL);
}
Shape getDrawableShape()
{
return new RectShape();
}
public Bitmap scaleImageWithColor(Drawable drawable, float scaleFactor, @ColorInt int color)
{
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
int sizeX = Math.round(drawable.getIntrinsicWidth() * scaleFactor);
int sizeY = Math.round(drawable.getIntrinsicHeight() * scaleFactor);
Bitmap bitmapResized = Bitmap.createScaledBitmap(b, sizeX, sizeY, true);
Canvas canvas = new Canvas(bitmapResized);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
paint.setAntiAlias(true);
ColorFilter filter = new LightingColorFilter(color, 1);
paint.setColorFilter(filter);
canvas.drawBitmap(bitmapResized, 0, 0, paint);
return bitmapResized;
}
protected Bitmap fromDrawable(final Drawable drawable, final int height, final int width)
{
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
public float getScaleIconFactor()
{
return scaleIconFactor;
}
public void setScaleIconFactor(float scaleIconFactor)
{
this.scaleIconFactor = scaleIconFactor;
}
public int getIconForegroundColor()
{
return iconForegroundColor;
}
public void setIconForegroundColor(int iconForegroundColor)
{
this.iconForegroundColor = iconForegroundColor;
}
public int getIconBackgroundColor()
{
return iconBackgroundColor;
}
public void setIconBackgroundColor(int iconBackgroundColor)
{
this.iconBackgroundColor = iconBackgroundColor;
}
public int getIconDrawable()
{
return iconDrawable;
}
public void setIconDrawable(int iconDrawable)
{
this.iconDrawable = iconDrawable;
}
}
Пользовательские атрибуты:
<declare-styleable name="DrawableRatingBarItem">
<attr name="scaleIconFactor" format="float"/>
<attr name="iconBackgroundColor" format="color"/>
<attr name="iconForegroundColor" format="color"/>
<attr name="iconDrawable" format="reference"/>
</declare-styleable>
Форма XML Drawables + RatingBar полный беспорядок.
Это настолько близко, насколько я мог бы найти решение без написания совершенно нового класса.
Мой расширенный класс строит правильно отображаемый прогресс для ProgressBar
зажимая это как требуется.
Замените ваши пустые и полные состояния теми, которые я предварительно заполнил. Не очень гибкий в данный момент, вы можете легко абстрагироваться от установки пустых / полных звездных состояний.
/**
* Created by chris on 28/08/2014.
* For Yoyo-Android.
*/
public class ShapeDrawableRatingBar extends RatingBar {
/**
* TileBitmap to base the width off of.
*/
@Nullable
private Bitmap mSampleTile;
public ShapeDrawableRatingBar(final Context context, final AttributeSet attrs) {
super(context, attrs);
setProgressDrawable(createProgressDrawable());
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mSampleTile != null) {
final int width = mSampleTile.getWidth() * getNumStars();
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
getMeasuredHeight());
}
}
protected LayerDrawable createProgressDrawable() {
final Drawable backgroundDrawable = createBackgroundDrawableShape();
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{
backgroundDrawable,
backgroundDrawable,
createProgressDrawableShape()
});
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.secondaryProgress);
layerDrawable.setId(2, android.R.id.progress);
return layerDrawable;
}
protected Drawable createBackgroundDrawableShape() {
final Bitmap tileBitmap = drawableToBitmap(getResources().getDrawable(R.drawable.ic_stamp_circle_empty));
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 shapeDrawable;
}
protected Drawable createProgressDrawableShape() {
final Bitmap tileBitmap = drawableToBitmap(getResources().getDrawable(R.drawable.ic_stamp_circle_full));
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
return new ClipDrawable(shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL);
}
Shape getDrawableShape() {
final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
return new RoundRectShape(roundedCorners, null, null);
}
public static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
int width = drawable.getIntrinsicWidth();
width = width > 0 ? width : 1;
int height = drawable.getIntrinsicHeight();
height = height > 0 ? height : 1;
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
призвание setMax
setMaxStars
звонки requestLayout
так что вы будете правильно измерять ширину. Не нужно отрабатывать android:minWidth
Просто установите android:layout_width="wrap_content"
,
Просто помните, что вам нужно будет добавить немного дополнения к вашему ShapeDrawables
как они повторяются от края до края.
Я копал исходный код RatingBar(и его родительского класса ProgressBar) и обнаружил, что ShapeDrawable отсутствует в tileify(), которая вызывается перед установкой progressDrawable в конструкторе ProgressBar:
private Drawable tileify(Drawable drawable, boolean clip) {
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 StateListDrawable) {
StateListDrawable in = (StateListDrawable) drawable;
StateListDrawable out = new StateListDrawable();
int numStates = in.getStateCount();
for (int i = 0; i < numStates; i++) {
out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
}
return out;
} 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;
}
Я не знаю, почему ShapeDrawable не был помещен туда, но я собираюсь добавить его в код подклассов.
Вы можете найти пошаговую оценку стилей бара здесь
попытаться установить <item name="android:progressDrawable">
к изображению вместо формы, если это работает, это означает, что ваша форма вызывает проблему