How to create Custom Ratings bar in Android

前端 未结 13 1248
故里飘歌
故里飘歌 2020-11-22 06:28

Hello all i need to perform Ratings in my application... SO i need to create custom Ratings bar... Can Anyone Help me in this?

13条回答
  •  -上瘾入骨i
    2020-11-22 07:08

    For SVG RatingBar I used RatingBar custom Vector Drawables superimposing and the answer of erdomester here. This solution traverses all drawables inside SvgRatingBar view of your layout, so in RecyclerView it has an overhead.

    SvgRatingBar.java:

    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapShader;
    import android.graphics.Canvas;
    import android.graphics.Shader;
    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.VectorDrawable;
    import android.graphics.drawable.shapes.RoundRectShape;
    import android.graphics.drawable.shapes.Shape;
    import android.os.Build;
    import android.support.graphics.drawable.VectorDrawableCompat;
    import android.support.v7.graphics.drawable.DrawableWrapper;
    import android.support.v7.widget.AppCompatRatingBar;
    import android.util.AttributeSet;
    import android.view.Gravity;
    
    public class SvgRatingBar extends AppCompatRatingBar {
    
        private Bitmap sampleTile;
    
        public SvgRatingBar(Context context) {
            this(context, null);
        }
    
        public SvgRatingBar(Context context, AttributeSet attrs) {
            this(context, attrs, android.support.v7.appcompat.R.attr.ratingBarStyle);
        }
    
        public SvgRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            LayerDrawable drawable = (LayerDrawable) createTile(getProgressDrawable(), false);
            setProgressDrawable(drawable);
        }
    
        /**
         * Converts a drawable to a tiled version of itself. It will recursively
         * traverse layer and state list drawables.
         */
        @SuppressLint("RestrictedApi")
        private Drawable createTile(Drawable drawable, boolean clip) {
            if (drawable instanceof DrawableWrapper) {
                Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
                if (inner != null) {
                    inner = createTile(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] = createTile(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 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
                final Bitmap tileBitmap = bitmapDrawable.getBitmap();
                if (sampleTile == null) {
                    sampleTile = tileBitmap;
                }
    
                final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
                final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
                        Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
                shapeDrawable.getPaint().setShader(bitmapShader);
                shapeDrawable.getPaint().setColorFilter(bitmapDrawable.getPaint().getColorFilter());
                return (clip) ? new ClipDrawable(shapeDrawable, Gravity.START,
                        ClipDrawable.HORIZONTAL) : shapeDrawable;
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
                return createTile(getBitmapDrawableFromVectorDrawable(drawable), clip);
            } else if (drawable instanceof VectorDrawableCompat) {
                // API 19 support.
                return createTile(getBitmapDrawableFromVectorDrawable(drawable), clip);
            }
            return drawable;
        }
    
        private BitmapDrawable getBitmapDrawableFromVectorDrawable(Drawable drawable) {
            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return new BitmapDrawable(getResources(), bitmap);
        }
    
        @Override
        protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (sampleTile != null) {
                final int width = sampleTile.getWidth() * getNumStars();
                setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
                        getMeasuredHeight());
            }
        }
    
        private Shape getDrawableShape() {
            final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
            return new RoundRectShape(roundedCorners, null, null);
        }
    }
    

    In your layout:

    
    

    You also have to create rating_bar.xml with two SVG drawables:

    
    
        
    
        
    
        
    
    
    

    In Kotlin.

    import android.annotation.SuppressLint
    import android.content.Context
    import android.graphics.Bitmap
    import android.graphics.BitmapShader
    import android.graphics.Canvas
    import android.graphics.Shader
    import android.graphics.drawable.*
    import android.graphics.drawable.shapes.RoundRectShape
    import android.os.Build
    import android.util.AttributeSet
    import android.view.Gravity
    import androidx.appcompat.R
    import androidx.appcompat.graphics.drawable.DrawableWrapper
    import androidx.appcompat.widget.AppCompatRatingBar
    import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
    
    class SvgRatingBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
                                                 defStyleAttr: Int = R.attr.ratingBarStyle) :
        AppCompatRatingBar(context, attrs, defStyleAttr) {
    
        private var sampleTile: Bitmap? = null
        private val roundedCorners = floatArrayOf(5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f)
        private val roundRectShape = RoundRectShape(roundedCorners, null, null)
    
        init {
            progressDrawable = createTile(progressDrawable, false) as LayerDrawable
        }
    
        /**
         * Converts a drawable to a tiled version of itself. It will recursively
         * traverse layer and state list drawables.
         */
        private fun createTile(drawable: Drawable, clip: Boolean): Drawable =
            when {
                drawable is DrawableWrapper -> {
                    @SuppressLint("RestrictedApi")
                    var inner = drawable.wrappedDrawable
                    if (inner != null) {
                        inner = createTile(inner, clip)
                        @SuppressLint("RestrictedApi")
                        drawable.wrappedDrawable = inner
                    }
                    drawable
                }
                drawable is LayerDrawable -> {
                    val n = drawable.numberOfLayers
                    val outDrawables = arrayOfNulls(n)
                    for (i in 0 until n) {
                        val id = drawable.getId(i)
                        outDrawables[i] = createTile(drawable.getDrawable(i),
                            id == android.R.id.progress || id == android.R.id.secondaryProgress)
                    }
                    val newBg = LayerDrawable(outDrawables)
                    for (i in 0 until n) {
                        newBg.setId(i, drawable.getId(i))
                    }
                    newBg
                }
                drawable is BitmapDrawable -> {
                    val tileBitmap = drawable.bitmap
                    if (sampleTile == null) {
                        sampleTile = tileBitmap
                    }
                    val bitmapShader = BitmapShader(tileBitmap, Shader.TileMode.REPEAT,
                        Shader.TileMode.CLAMP)
                    val shapeDrawable = ShapeDrawable(roundRectShape).apply {
                        paint.shader = bitmapShader
                        paint.colorFilter = drawable.paint.colorFilter
                    }
                    if (clip) ClipDrawable(shapeDrawable, Gravity.START, ClipDrawable.HORIZONTAL)
                    else shapeDrawable
                }
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable is VectorDrawable -> {
                    createTile(getBitmapDrawableFromVectorDrawable(drawable), clip)
                }
                drawable is VectorDrawableCompat -> {
                    // Pre-Lollipop support.
                    createTile(getBitmapDrawableFromVectorDrawable(drawable), clip)
                }
                else -> drawable
            }
    
        private fun getBitmapDrawableFromVectorDrawable(drawable: Drawable): BitmapDrawable {
            val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight,
                Bitmap.Config.ARGB_8888)
            val canvas = Canvas(bitmap)
            drawable.setBounds(0, 0, canvas.width, canvas.height)
            drawable.draw(canvas)
            return BitmapDrawable(resources, bitmap)
        }
    
        @Synchronized override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            if (sampleTile != null) {
                val width = sampleTile!!.width * numStars
                setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
                    measuredHeight)
            }
        }
    }
    

提交回复
热议问题