Wednesday, April 25, 2018

Android - Circular image view with loader


Introduction:- Reusable component always increase the speed of development. So,  i'm going to explain a component that displays image in the circular shape that's written in Kotlin.

For display user profile pic we always need a circular image view.  Let's dive in the code snippet.

First of all, you need to add it in your layout file: activity_main
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true"
    android:focusable="true"
    android:orientation="vertical"
    >
        <com.demo.CircularImageView
            android:id="@+id/fragment_tv_user_pic"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="22dp"
            app:civ_border_color="@color/colorWhite"
            app:civ_border_width="2dp"
            app:matProg_barColor="@color/colorAccent"
            app:matProg_barWidth="2dp"
            app:matProg_circleRadius="60dp"
            app:matProg_progressIndeterminate="true"
            />
   </LinearLayout>


Example-1:

If you want display short form of the name in this component. Use the following code snippet.
 val civUserPic = findViewById<CircularImageView>(R.id.fragment_tv_user_pic)
 civUserPic.createTextPaint("#2CB044", 60, true)
 civUserPic.setText("S.K")
Output:





Example-2:

If you want to display image from res folder in this component. Use the following code snippet.
  civUserPic.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.images))
  civUserPic.setBorderColor(R.color.colorPrimary)

Output:



Example-3:

If you want to display image from the server and you have full path of image use following steps. You can use any  image loader lib like here i'm using Picasso
       civUserPic.loaderState(true)
       civUserPic.invalidate()
       Picasso.with(this).load("image_url").into(civUserPic)

Output:




So, time to view component.

values/attrs:-


<?xml version="1.0" encoding="utf-8"?>
<resources>

     <declare-styleable name="ProgressWheel">
        <attr name="matProg_progressIndeterminate" format="boolean"/>
        <attr name="matProg_barColor" format="color"/>
        <attr name="matProg_rimColor" format="color"/>
        <attr name="matProg_rimWidth" format="dimension"/>
        <attr name="matProg_spinSpeed" format="float"/>
        <attr name="matProg_barSpinCycleTime" format="integer"/>
        <attr name="matProg_circleRadius" format="dimension"/>
        <attr name="matProg_fillRadius" format="boolean"/>
        <attr name="matProg_barWidth" format="dimension"/>
        <attr name="matProg_linearProgress" format="boolean"/>
        <attr name="matProg_visible" format="boolean"/>
     </declare-styleable>

    <declare-styleable name="CircularImageView">
        <attr name="civ_border_width" format="dimension" />
        <attr name="civ_border_color" format="color" />
        <attr name="civ_border_overlay" format="boolean" />
        <attr name="civ_fad_overlay" format="boolean" />
        <attr name="civ_fill_color" format="color" />
    </declare-styleable>

</resources>



CircularImageView.Kt:-
class CircularImageView : AppCompatImageView {
    private val mDrawableRect = RectF()
    private val mBorderRect = RectF()
    private val mShaderMatrix = Matrix()
    private val mBitmapPaint = Paint()
    private val mBorderPaint = Paint()
    private val mFillPaint = Paint()
    private var mBorderColor = DEFAULT_BORDER_COLOR
    private var mBorderWidth = DEFAULT_BORDER_WIDTH
    private var mFillColor = DEFAULT_FILL_COLOR
    private var mBitmap: Bitmap? = null
    private var mBitmapShader: BitmapShader? = null
    private var mBitmapWidth: Int = 0
    private var mBitmapHeight: Int = 0
    private var mDrawableRadius: Float = 0.toFloat()
    private var mBorderRadius: Float = 0.toFloat()
    private var mColorFilter: ColorFilter? = null
    private var mReady: Boolean = false
    private var mSetupPending: Boolean = false
    private var mBorderOverlay: Boolean = false
    private val barLength = 16
    //Sizes (with defaults in DP)
    private var circleRadius = 28
    private var barWidth = 4
    private var rimWidth = 4
    private var fillRadius = false
    private var timeStartGrowing = 0.0
    private var barSpinCycleTime = 460.0
    private var barExtraLength = 0f
    private var barGrowingFromFront = true
    private var pausedTimeWithoutGrowing: Long = 0
    //Colors (with defaults)
    private var barColor = -0x56000000
    private var rimColor = 0x00FFFFFF
    //Paints
    private val barPaint = Paint()
    private val rimPaint = Paint()
    //Rectangles
    private var circleBounds = RectF()
    //Animation
    //The amount of degrees per second
    private var spinSpeed = 230.0f
    // The last time the spinner was animated
    private var lastTimeAnimated: Long = 0
    private var linearProgress: Boolean = false
    var isProgressVisible: Boolean = false
    private var mProgress = 0.0f
    private var mTargetProgress = 0.0f
    private var isSpinning = false
    private var callback: ProgressCallback? = null
    private var mFadEnable: Boolean=false
    private var fadPaint: Paint? = null
    private var fad: Int = 0
    private var textPaint: Paint? = null
    private var text: String? = null
    private var isBorderRequired: Boolean = false
  
    constructor(context: Context) : super(context) {
        init()
    }
  
    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) {
        parseAttributes(context.obtainStyledAttributes(attrs,
                R.styleable.ProgressWheel))
    }
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0)
        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircularImageView_civ_border_width, DEFAULT_BORDER_WIDTH)
        mBorderColor = a.getColor(R.styleable.CircularImageView_civ_border_color, DEFAULT_BORDER_COLOR)
        mBorderOverlay = a.getBoolean(R.styleable.CircularImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY)
        mFadEnable = a.getBoolean(R.styleable.CircularImageView_civ_fad_overlay, DEFAULT_BORDER_OVERLAY)
        mFillColor = a.getColor(R.styleable.CircularImageView_civ_fill_color, DEFAULT_FILL_COLOR)
        a.recycle()
        init()
    }
  
    private fun init() {
        super.setScaleType(SCALE_TYPE)
        mReady = true
        if (mSetupPending) {
            setup()
            mSetupPending = false
        }
    }
    override fun getScaleType(): ImageView.ScaleType {
        return SCALE_TYPE
    }
    override fun setScaleType(scaleType: ImageView.ScaleType) {
        if (scaleType != SCALE_TYPE) {
            throw IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType))
        }
    }
    override fun setAdjustViewBounds(adjustViewBounds: Boolean) {
        if (adjustViewBounds) {
            throw IllegalArgumentException("adjustViewBounds not supported.")
        }
    }
    override fun onDraw(canvas: Canvas) {
        if (mBitmap != null) {
            //draw image
            if (mFillColor != Color.TRANSPARENT) {
                canvas.drawCircle(width / 2.0f, height / 2.0f, mDrawableRadius, mFillPaint)
            }
            canvas.drawCircle(width / 2.0f, height / 2.0f, mDrawableRadius, mBitmapPaint)
            if (mBorderWidth != 0) {
                canvas.drawCircle(width / 2.0f, height / 2.0f, mBorderRadius, mBorderPaint)
            }
            isProgressVisible = false
        } else if (text != null && !text!!.isEmpty() && textPaint != null) {
            if (isBorderRequired && mBorderWidth != 0) {
                canvas.drawCircle(width / 2.0f, height / 2.0f, mBorderRadius, mBorderPaint)
            }
            canvas.drawText(text!!, width / 2.0f - textPaint!!.measureText(text) / 2, height / 2.0f - (textPaint!!.descent() + textPaint!!.ascent()) / 2, textPaint!!)
        }
        if (mFadEnable && fadPaint != null) {
            fadPaint!!.alpha = fad
            canvas.drawCircle(width / 2.0f, height / 2.0f, mDrawableRadius, fadPaint!!)
        }
        //draw progress bar
        if (isProgressVisible) {
            drawProgressBar(canvas)
        }
    }
    fun loaderState(state: Boolean) {
        isProgressVisible = state
    }
    private fun drawProgressBar(canvas: Canvas) {
        canvas.drawArc(circleBounds, 360f, 360f, false, rimPaint)
        var mustInvalidate = false
        if (isSpinning) {
            //Draw the spinning bar
            mustInvalidate = true
            val deltaTime = SystemClock.uptimeMillis() - lastTimeAnimated
            val deltaNormalized = deltaTime * spinSpeed / 1000.0f
            updateBarLength(deltaTime)
            mProgress += deltaNormalized
            if (mProgress > 360) {
                mProgress -= 360f
                // A full turn has been completed
                // we run the callback with -1 in case we want to
                // do something, like changing the color
                runCallback(-1.0f)
            }
            lastTimeAnimated = SystemClock.uptimeMillis()
            var from = mProgress - 90
            var length = barLength + barExtraLength
            if (isInEditMode) {
                from = 0f
                length = 135f
            }
            canvas.drawArc(circleBounds, from, length, false,
                    barPaint)
        } else {
            val oldProgress = mProgress
            if (mProgress != mTargetProgress) {
                //We smoothly increase the progress bar
                mustInvalidate = true
                val deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated).toFloat() / 1000
                val deltaNormalized = deltaTime * spinSpeed
                mProgress = Math.min(mProgress + deltaNormalized, mTargetProgress)
                lastTimeAnimated = SystemClock.uptimeMillis()
            }
            if (oldProgress != mProgress) {
                runCallback()
            }
            var offset = 0.0f
            var progress = mProgress
            if (!linearProgress) {
                val factor = 2.0f
                offset = (1.0f - Math.pow((1.0f - mProgress / 360.0f).toDouble(), (2.0f * factor).toDouble())).toFloat() * 360.0f
                progress = (1.0f - Math.pow((1.0f - mProgress / 360.0f).toDouble(), factor.toDouble())).toFloat() * 360.0f
            }
            if (isInEditMode) {
                progress = 360f
            }
            canvas.drawArc(circleBounds, offset - 90, progress, false, barPaint)
        }
        if (mustInvalidate) {
            invalidate()
        }
    }
    override fun onSizeChanged(w: Int, h: Int, oldW: Int, oldH: Int) {
        super.onSizeChanged(w, h, oldW, oldH)
        setUpBounds(w, h)
        setupPaints()
        setup()
    }
    override fun setImageBitmap(bm: Bitmap) {
        super.setImageBitmap(bm)
        mBitmap = bm
        setup()
    }
    override fun setImageDrawable(drawable: Drawable?) {
        super.setImageDrawable(drawable)
        mBitmap = getBitmapFromDrawable(drawable)
        setup()
    }
    override fun setImageResource(@DrawableRes resId: Int) {
        super.setImageResource(resId)
        mBitmap = getBitmapFromDrawable(drawable)
        setup()
    }
    override fun setImageURI(uri: Uri?) {
        super.setImageURI(uri)
        mBitmap = if (uri != null) getBitmapFromDrawable(drawable) else null
        setup()
    }
    override fun setColorFilter(cf: ColorFilter) {
        if (cf === mColorFilter) {
            return
        }
        mColorFilter = cf
        mBitmapPaint.colorFilter = mColorFilter
        invalidate()
    }
   
    private fun getBitmapFromDrawable(drawable: Drawable?): Bitmap? {
        if (drawable == null) {
            return null
        }
        if (drawable is BitmapDrawable) {
            return drawable.bitmap
        }
        try {
            val bitmap: Bitmap
            if (drawable is ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG)
            } else {
                bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG)
            }
            val canvas = Canvas(bitmap)
            drawable.setBounds(0, 0, canvas.width, canvas.height)
            drawable.draw(canvas)
            return bitmap
        } catch (e: Exception) {
            Log.d("error", e.toString())
            return null
        }
    }
    private fun setup() {
        if (!mReady) {
            mSetupPending = true
            return
        }
        if (width == 0 && height == 0) {
            return
        }
        mBorderPaint.style = Paint.Style.STROKE
        mBorderPaint.isAntiAlias = true
        mBorderPaint.color = mBorderColor
        mBorderPaint.strokeWidth = mBorderWidth.toFloat()
        mFillPaint.style = Paint.Style.FILL
        mFillPaint.isAntiAlias = true
        mFillPaint.color = mFillColor
        mBorderRect.set(0f, 0f, width.toFloat(), height.toFloat())
        mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f)
        mDrawableRect.set(mBorderRect)
        if (!mBorderOverlay) {
            mDrawableRect.inset(mBorderWidth.toFloat(), mBorderWidth.toFloat())
        }
        mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f)
        if (mBitmap == null) {
            invalidate()
            return
        }
        mBitmapShader = BitmapShader(mBitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        mBitmapPaint.isAntiAlias = true
        mBitmapPaint.shader = mBitmapShader
        mBitmapHeight = mBitmap!!.height
        mBitmapWidth = mBitmap!!.width
        updateShaderMatrix()
        invalidate()
    }
    fun setBorderColor(color: Int) {
        mBorderColor = color
        mBorderPaint.color = mBorderColor
        invalidate()
    }
    private fun updateShaderMatrix() {
        val scale: Float
        var dx = 0f
        var dy = 0f
        mShaderMatrix.set(null)
        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
            scale = mDrawableRect.height() / mBitmapHeight.toFloat()
            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f
        } else {
            scale = mDrawableRect.width() / mBitmapWidth.toFloat()
            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f
        }
        mShaderMatrix.setScale(scale, scale)
        mShaderMatrix.postTranslate((dx + 0.5f).toInt() + mDrawableRect.left, (dy + 0.5f).toInt() + mDrawableRect.top)
        mBitmapShader!!.setLocalMatrix(mShaderMatrix)
    }
    fun createFadPaint(color: String) {
        fadPaint = Paint()
        fadPaint!!.style = Paint.Style.FILL
        fadPaint!!.isAntiAlias = true
        fadPaint!!.color = Color.parseColor(color)
    }
    fun createTextPaint(color: String, fontSize: Int, isBorderRequired: Boolean) {
        textPaint = Paint()
        textPaint!!.style = Paint.Style.FILL
        textPaint!!.isAntiAlias = true
        textPaint!!.color = Color.parseColor(color)
        textPaint!!.textSize = fontSize.toFloat()
        this.isBorderRequired = isBorderRequired
    }
    fun setText(text: String) {
        this.text = text
        mBitmap = null
        Log.i(">>>", "" + text)
        invalidate()
    }
    fun setFad(fad: Int) {
        this.fad = fad
        Log.i(">>>", "" + fad)
        invalidate()
    }
  
    interface ProgressCallback {
    
        fun onProgressUpdate(progress: Float)
    }
  
    private fun parseAttributes(a: TypedArray) {
        // We transform the default values from DIP to pixels
        val metrics = context.resources.displayMetrics
        barWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, barWidth.toFloat(), metrics).toInt()
        rimWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rimWidth.toFloat(), metrics).toInt()
        circleRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, circleRadius.toFloat(), metrics).toInt()
        circleRadius = a.getDimension(R.styleable.ProgressWheel_matProg_circleRadius, circleRadius.toFloat()).toInt()
        fillRadius = a.getBoolean(R.styleable.ProgressWheel_matProg_fillRadius, false)
        barWidth = a.getDimension(R.styleable.ProgressWheel_matProg_barWidth, barWidth.toFloat()).toInt()
        rimWidth = a.getDimension(R.styleable.ProgressWheel_matProg_rimWidth, rimWidth.toFloat()).toInt()
        val baseSpinSpeed = a.getFloat(R.styleable.ProgressWheel_matProg_spinSpeed, spinSpeed / 360.0f)
        spinSpeed = baseSpinSpeed * 360
        barSpinCycleTime = a.getInt(R.styleable.ProgressWheel_matProg_barSpinCycleTime, barSpinCycleTime.toInt()).toDouble()
        barColor = a.getColor(R.styleable.ProgressWheel_matProg_barColor, barColor)
        rimColor = a.getColor(R.styleable.ProgressWheel_matProg_rimColor, rimColor)
        isProgressVisible = a.getBoolean(R.styleable.ProgressWheel_matProg_visible, false)
        linearProgress = a.getBoolean(R.styleable.ProgressWheel_matProg_linearProgress, false)
        if (a.getBoolean(R.styleable.ProgressWheel_matProg_progressIndeterminate, false)) {
            spin()
        }
        // Recycle
        a.recycle()
    }
    private fun spin() {
        lastTimeAnimated = SystemClock.uptimeMillis()
        isSpinning = true
        invalidate()
    }
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val viewWidth = circleRadius + this.paddingLeft + this.paddingRight
        val viewHeight = circleRadius + this.paddingTop + this.paddingBottom
        val widthMode = View.MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = View.MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = View.MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = View.MeasureSpec.getSize(heightMeasureSpec)
        val width: Int
        val height: Int
        //Measure Width
        if (widthMode == View.MeasureSpec.EXACTLY) {
            //Must be this size
            width = widthSize
        } else if (widthMode == View.MeasureSpec.AT_MOST) {
            //Can't be bigger than...
            width = Math.min(viewWidth, widthSize)
        } else {
            //Be whatever you want
            width = viewWidth
        }
        //Measure Height
        if (heightMode == View.MeasureSpec.EXACTLY || widthMode == View.MeasureSpec.EXACTLY) {
            //Must be this size
            height = heightSize
        } else if (heightMode == View.MeasureSpec.AT_MOST) {
            //Can't be bigger than...
            height = Math.min(viewHeight, heightSize)
        } else {
            //Be whatever you want
            height = viewHeight
        }
        setMeasuredDimension(width, height)
    }
 private fun setUpBounds(layoutWidth: Int, layoutHeight: Int) {
        val paddingTop = paddingTop
        val paddingBottom = paddingBottom
        val paddingLeft = paddingLeft
        val paddingRight = paddingRight
        if (!fillRadius) {
            // Width should equal to Height, find the min value to setup the circle
            val minValue = Math.min(layoutWidth - paddingLeft - paddingRight,
                    layoutHeight - paddingBottom - paddingTop)
            val circleDiameter = Math.min(minValue, circleRadius * 2 - barWidth * 2)
            // Calc the Offset if needed for centering the wheel in the available space
            val xOffset = (layoutWidth - paddingLeft - paddingRight - circleDiameter) / 2 + paddingLeft
            val yOffset = (layoutHeight - paddingTop - paddingBottom - circleDiameter) / 2 + paddingTop
            circleBounds = RectF((xOffset + barWidth).toFloat(),
                    (yOffset + barWidth).toFloat(),
                    (xOffset + circleDiameter - barWidth).toFloat(),
                    (yOffset + circleDiameter - barWidth).toFloat())
        } else {
            circleBounds = RectF((paddingLeft + barWidth).toFloat(),
                    (paddingTop + barWidth).toFloat(),
                    (layoutWidth - paddingRight - barWidth).toFloat(),
                    (layoutHeight - paddingBottom - barWidth).toFloat())
        }
    }
  
 private fun setupPaints() {
        barPaint.color = barColor
        barPaint.isAntiAlias = true
        barPaint.style = Paint.Style.STROKE
        barPaint.strokeWidth = barWidth.toFloat()
        rimPaint.color = rimColor
        rimPaint.isAntiAlias = true
        rimPaint.style = Paint.Style.STROKE
        rimPaint.strokeWidth = rimWidth.toFloat()
    }
  fun setCallback(progressCallback: ProgressCallback) {
        callback = progressCallback
        if (!isSpinning) {
            runCallback()
        }
    }
    private fun runCallback() {
        if (callback != null) {
            val normalizedProgress = Math.round(mProgress * 100 / 360.0f).toFloat() / 100
            callback!!.onProgressUpdate(normalizedProgress)
        }
    }
    private fun runCallback(value: Float) {
        if (callback != null) {
            callback!!.onProgressUpdate(value)
        }
    }
    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        if (visibility == View.VISIBLE) {
            lastTimeAnimated = SystemClock.uptimeMillis()
        }
    }
    private fun updateBarLength(deltaTimeInMilliSeconds: Long) {
        if (pausedTimeWithoutGrowing >= 200) {
            timeStartGrowing += deltaTimeInMilliSeconds.toDouble()
            if (timeStartGrowing > barSpinCycleTime) {
                // We completed a size change cycle
                // (growing or shrinking)
                timeStartGrowing -= barSpinCycleTime
                pausedTimeWithoutGrowing = 0
                barGrowingFromFront = !barGrowingFromFront
            }
            val distance = Math.cos((timeStartGrowing / barSpinCycleTime + 1) * Math.PI).toFloat() / 2 + 0.5f
            val destLength = 270.toFloat() - barLength
            if (barGrowingFromFront) {
                barExtraLength = distance * destLength
            } else {
                val newLength = destLength * (1 - distance)
                mProgress += barExtraLength - newLength
                barExtraLength = newLength
            }
        } else {
            pausedTimeWithoutGrowing += deltaTimeInMilliSeconds
        }
    }
  
    fun stopSpinning() {
        isSpinning = false
        mProgress = 0.0f
        mTargetProgress = 0.0f
        invalidate()
    }
    public override fun onSaveInstanceState(): Parcelable? {
        val superState = super.onSaveInstanceState()
        val ss = WheelSavedState(superState)
        // We save everything that can be changed at runtime
        ss.mProgress = this.mProgress
        ss.mTargetProgress = this.mTargetProgress
        ss.isSpinning = this.isSpinning
        ss.spinSpeed = this.spinSpeed
        ss.barWidth = this.barWidth
        ss.barColor = this.barColor
        ss.rimWidth = this.rimWidth
        ss.rimColor = this.rimColor
        ss.circleRadius = this.circleRadius
        ss.linearProgress = this.linearProgress
        ss.fillRadius = this.fillRadius
        return ss
    }
    public override fun onRestoreInstanceState(state: Parcelable) {
        if (state !is WheelSavedState) {
            super.onRestoreInstanceState(state)
            return
        }
        super.onRestoreInstanceState(state.superState)
        this.mProgress = state.mProgress
        this.mTargetProgress = state.mTargetProgress
        this.isSpinning = state.isSpinning
        this.spinSpeed = state.spinSpeed
        this.barWidth = state.barWidth
        this.barColor = state.barColor
        this.rimWidth = state.rimWidth
        this.rimColor = state.rimColor
        this.circleRadius = state.circleRadius
        this.linearProgress = state.linearProgress
        this.fillRadius = state.fillRadius
        this.lastTimeAnimated = SystemClock.uptimeMillis()
    }
   
    internal class WheelSavedState : View.BaseSavedState {
      
        var mProgress: Float = 0.toFloat()
        
        var mTargetProgress: Float = 0.toFloat()
      
        var isSpinning: Boolean = false
      
        var spinSpeed: Float = 0.toFloat()
      
        var barWidth: Int = 0
        
        var barColor: Int = 0
        
        var rimWidth: Int = 0
      
        var rimColor: Int = 0
        
        var circleRadius: Int = 0
       
        var linearProgress: Boolean = false
       
        var fillRadius: Boolean = false
        constructor(superState: Parcelable) : super(superState) {}
        private constructor(`in`: Parcel) : super(`in`) {
            this.mProgress = `in`.readFloat()
            this.mTargetProgress = `in`.readFloat()
            this.isSpinning = `in`.readByte().toInt() != 0
            this.spinSpeed = `in`.readFloat()
            this.barWidth = `in`.readInt()
            this.barColor = `in`.readInt()
            this.rimWidth = `in`.readInt()
            this.rimColor = `in`.readInt()
            this.circleRadius = `in`.readInt()
            this.linearProgress = `in`.readByte().toInt() != 0
            this.fillRadius = `in`.readByte().toInt() != 0
        }
        override fun writeToParcel(out: Parcel, flags: Int) {
            super.writeToParcel(out, flags)
            out.writeFloat(this.mProgress)
            out.writeFloat(this.mTargetProgress)
            out.writeByte((if (isSpinning) 1 else 0).toByte())
            out.writeFloat(this.spinSpeed)
            out.writeInt(this.barWidth)
            out.writeInt(this.barColor)
            out.writeInt(this.rimWidth)
            out.writeInt(this.rimColor)
            out.writeInt(this.circleRadius)
            out.writeByte((if (linearProgress) 1 else 0).toByte())
            out.writeByte((if (fillRadius) 1 else 0).toByte())
        }
        companion object {
          
            //required field that makes Parcelables from a Parcel
            val CREATOR: Parcelable.Creator<WheelSavedState> = object : Parcelable.Creator<WheelSavedState> {
                override fun createFromParcel(`in`: Parcel): WheelSavedState {
                    return WheelSavedState(`in`)
                }
                override fun newArray(size: Int): Array<WheelSavedState?> {
                    return arrayOfNulls(size)
                }
            }
        }
    }
    companion object {
        private val SCALE_TYPE = ImageView.ScaleType.CENTER_CROP
        private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888
        private val COLOR_DRAWABLE_DIMENSION = 2
        private val DEFAULT_BORDER_WIDTH = 0
        private val DEFAULT_BORDER_COLOR = Color.BLACK
        private val DEFAULT_FILL_COLOR = Color.TRANSPARENT
        private val DEFAULT_BORDER_OVERLAY = false
    }
}



Let me know if you facing issue to use it.



Share:

Get it on Google Play

React Native - Start Development with Typescript

React Native is a popular framework for building mobile apps for both Android and iOS. It allows developers to write JavaScript code that ca...