【问题标题】:ShapeDrawable as progressDrawable for RatingBar in Android?ShapeDrawable作为Android中RatingBar的progressDrawable?
【发布时间】:2013-10-10 11:55:12
【问题描述】:

似乎我无法将 ShapeDrawable 设置为 Ratingbar 的 progressDrawable。我尝试了以下方法但失败了:

<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 代替 shape 适用于该行:

@drawable/ratingbar_full

【问题讨论】:

    标签: android android-ui ratingbar shapedrawable


    【解决方案1】:

    Shape 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;
        }
    
    } 
    

    调用setMaxsetMaxStars 调用requestLayout,这样您就可以正确测量宽度。无需计算android:minWidth,只需设置android:layout_width="wrap_content"

    请记住,您需要在 ShapeDrawables 中添加一些填充,因为它们会边对边重复。

    【讨论】:

      【解决方案2】:

      我自定义了@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>
      

      【讨论】:

      • 仅供任何未来的读者看到 - 这很完美。但是使用您使用的 ColorFilter,它会在将颜色添加到可绘制对象时乘以颜色。我建议你使用 ColorFilter filter = new LightingColorFilter(0, color);替换原来的颜色。
      • 谢谢我去看看!
      【解决方案3】:

      我挖掘RatingBar(及其父类ProgressBar)源代码,发现在ProgressBar构造函数中设置progressDrawable之前调用的tileify()中缺少ShapeDrawable:

      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 没有放在那里,但我正在考虑将它添加到子类代码中。

      【讨论】:

        【解决方案4】:

        您可以找到一步一步的评级栏样式here
        尝试将&lt;item name="android:progressDrawable"&gt; 设置为图像而不是形状,如果可行,则意味着您的形状导致了问题

        【讨论】:

        • 为什么Bitmap可以,ShapeDrawable不能?
        • 不知道!但由于它可以将形状创建为 png 并使用它
        猜你喜欢
        • 2015-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-26
        • 1970-01-01
        • 2016-01-31
        相关资源
        最近更新 更多