Horizontally of circular images to show user profile picture

后端 未结 3 892
小鲜肉
小鲜肉 2021-01-19 14:59

I need to show the users profile picture who all are joining in a specified event and it should be in horizontal circular images one after other and after 5 images. it shoul

3条回答
  •  一向
    一向 (楼主)
    2021-01-19 15:26

    OverlapImageViewActivity.kt

    class OverlapImageViewActivity : AppCompatActivity(), RecyclerViewClickListener {
    
        private val mAdapter by lazy { OverlapRecyclerViewAdapter(this, this,overlapLimit) }
    
        //------limit number of items to be overlapped
        private val overlapLimit = 5
    
        //------set value of item overlapping
        private val overlapWidth = -50
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            //------create dummy list to set on recycler view
            setDummyArrayList()
    
            //------set up recycler view
            val layoutManager = LinearLayoutManager(this,
                    LinearLayoutManager.HORIZONTAL, false)
            recyclerView.layoutManager = layoutManager
    
            //------set item decoration for item overlapping
            recyclerView.addItemDecoration(OverlapRecyclerViewDecoration(overlapLimit, overlapWidth))
            recyclerView.adapter = mAdapter
            mAdapter.setImageList(setDummyArrayList())
    
        }
    
        /**
         * add dummy data to ArrayList
         */
        private fun setDummyArrayList(): ArrayList {
            val mArrayList = ArrayList()
    
            //-----fill data in to array list
            for (i in 0..30) {
                val imageModel = OverlapImageModel()
                imageModel.imageUrl = imageURLs[i % imageURLs.size]
                mArrayList.add(imageModel)
            }
    
            return mArrayList
        }
    
        override fun onNormalItemClicked(adapterPosition: Int) {
            toast(this,"Normal item clicked >> $adapterPosition")
        }
    
        override fun onNumberedItemClick(adapterPosition: Int) {
            toast(this,"Numbered item clicked >> $adapterPosition")
        }
    }
    

    activity_main.xml

    
    
    
    
        
    
    
    

    OverLapRecyclerViewAdapter.kt

    class OverlapRecyclerViewAdapter(private var mContext: Context, private var recyclerViewClickListener: RecyclerViewClickListener
                                     , private val overlapLimit: Int) : RecyclerView.Adapter() {
    
        private val TAG = OverlapRecyclerViewAdapter::class.java.simpleName
    
        //----array list to be shown
        private var mImageList = ArrayList()
    
        //----array list to be shown after expansion
        private var mImageExpandedList = ArrayList()
    
        //----flag to indicate recyclerview is expanded or not
        private var isExpanded = false
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
            val view = LayoutInflater.from(mContext).inflate(R.layout.row_image, parent, false)
            return CustomViewHolder(view)
        }
    
        override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
            val mCurrentImageModel = mImageList[position]
    
            //----bind data to view
            holder.bind(mCurrentImageModel)
        }
    
        /**
         * set array list over adapter
         */
        fun setImageList(mImageList: ArrayList) {
            if (mImageList.size > overlapLimit) {
                for (mImageModel in mImageList) {
                    if (this.mImageList.size <= overlapLimit) {
                        this.mImageList.add(mImageModel)
                    } else {
                        this.mImageExpandedList.add(mImageModel)
                    }
                }
            } else {
                this.mImageList = mImageList
            }
            notifyDataSetChanged()
        }
    
        /**
         * add items to array list
         */
        fun addItems(mImageList: ArrayList) {
            this.mImageList.addAll(mImageList)
            notifyDataSetChanged()
        }
    
        override fun getItemCount(): Int {
            return mImageList.size
        }
    
        /**
         * get item by its position
         */
        fun getItem(pos: Int): OverlapImageModel {
            return mImageList[pos]
        }
    
        inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    
            private var requestOptions: RequestOptions? = null
    
            /**
             * init request option for glide
             */
            private fun getGlideRequestOptions(): RequestOptions {
                if (requestOptions == null) {
                    requestOptions = RequestOptions()
                    requestOptions?.error(R.mipmap.ic_launcher)
                    requestOptions?.placeholder(R.mipmap.ic_launcher)
                }
                return requestOptions!!
            }
    
            /**
             * bind model data to item
             */
            fun bind(mImageModel: OverlapImageModel) {
    
                if (adapterPosition == overlapLimit && !isExpanded) {
    
                    //----set text drawable to show count on last imageview
                    val text = mImageExpandedList.size.toString()
                    val drawable = TextDrawable.builder()
                            .beginConfig()
                            .textColor(Color.WHITE)
                            .width(90)
                            .height(90)
                            .endConfig()
                            .buildRound(text, Color.parseColor("#8FAE5D"))
                    itemView.imageView.setImageDrawable(drawable)
                } else {
    
                    //----load image
                    Glide.with(mContext)
                            .load(mImageModel.imageUrl)
                            .apply(getGlideRequestOptions())
                            .into(itemView.imageView)
                }
    
                //----handle item click
                itemView.imageView.setOnClickListener {
                    if (adapterPosition == overlapLimit && !isExpanded) {
                        recyclerViewClickListener.onNumberedItemClick(adapterPosition)
                    } else {
                        recyclerViewClickListener.onNormalItemClicked(adapterPosition)
                    }
                }
            }
        }
    }
    

    OverlapRecyclerViewDecoration.kt

    class OverlapRecyclerViewDecoration(private val overlapLimit: Int, private val overlapWidth: Int) : RecyclerView.ItemDecoration() {
        override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
    
            //-----get current position of item
            val itemPosition = parent.getChildAdapterPosition(view)
    
            //-----avoid first item decoration else it will go of the screen
            if (itemPosition == 0) {
                return
            } else {
    
                //-----apply decoration
                when {
                    itemPosition <= overlapLimit -> outRect.set(overlapWidth, 0, 0, 0)
    
                    else -> outRect.set(0, 0, 0, 0)
                }
            }
        }
    }
    

    TextDrawable.kt

    class TextDrawable(builder: Builder) : ShapeDrawable(builder.shape) {
    
        private val textPaint: Paint
        private val borderPaint: Paint
        private val text: String?
        private val color: Int
        private val shape: RectShape?
        private val height: Int
        private val width: Int
        private val fontSize: Int
        private val radius: Float
        private val borderThickness: Int
    
        init {
    
            // shape properties
            shape = builder.shape
            height = builder.height
            width = builder.width
            radius = builder.radius
    
            // text and color
            text = if (builder.toUpperCase) builder.text!!.toUpperCase() else builder.text
            color = builder.color
    
            // text paint settings
            fontSize = builder.fontSize
            textPaint = Paint()
            textPaint.color = builder.textColor
            textPaint.isAntiAlias = true
            textPaint.isFakeBoldText = builder.isBold
            textPaint.style = Paint.Style.FILL
            textPaint.typeface = builder.font
            textPaint.textAlign = Paint.Align.CENTER
            textPaint.strokeWidth = builder.borderThickness.toFloat()
    
            // border paint settings
            borderThickness = builder.borderThickness
            borderPaint = Paint()
            borderPaint.color = getDarkerShade(builder.color)
            borderPaint.style = Paint.Style.STROKE
            borderPaint.strokeWidth = borderThickness.toFloat()
    
            // drawable paint color
            val paint = paint
            paint.color = color
    
        }
    
        private fun getDarkerShade(color: Int): Int {
            return Color.rgb((SHADE_FACTOR * Color.red(color)).toInt(),
                    (SHADE_FACTOR * Color.green(color)).toInt(),
                    (SHADE_FACTOR * Color.blue(color)).toInt())
        }
    
        override fun draw(canvas: Canvas) {
            super.draw(canvas)
            val r = bounds
    
    
            // draw border
            if (borderThickness > 0) {
                drawBorder(canvas)
            }
    
            val count = canvas.save()
            canvas.translate(r.left.toFloat(), r.top.toFloat())
    
            // draw text
            val width = if (this.width < 0) r.width() else this.width
            val height = if (this.height < 0) r.height() else this.height
            val fontSize = if (this.fontSize < 0) Math.min(width, height) / 2 else this.fontSize
            textPaint.textSize = fontSize.toFloat()
            canvas.drawText(text!!, (width / 2).toFloat(), height / 2 - (textPaint.descent() + textPaint.ascent()) / 2, textPaint)
    
            canvas.restoreToCount(count)
    
        }
    
        private fun drawBorder(canvas: Canvas) {
            val rect = RectF(bounds)
            rect.inset((borderThickness / 2).toFloat(), (borderThickness / 2).toFloat())
    
            when (shape) {
                is OvalShape -> canvas.drawOval(rect, borderPaint)
                is RoundRectShape -> canvas.drawRoundRect(rect, radius, radius, borderPaint)
                else -> canvas.drawRect(rect, borderPaint)
            }
        }
    
        override fun setAlpha(alpha: Int) {
            textPaint.alpha = alpha
        }
    
        override fun setColorFilter(cf: ColorFilter?) {
            textPaint.colorFilter = cf
        }
    
        override fun getOpacity(): Int {
            return PixelFormat.TRANSLUCENT
        }
    
        override fun getIntrinsicWidth(): Int {
            return width
        }
    
        override fun getIntrinsicHeight(): Int {
            return height
        }
    
        class Builder : IConfigBuilder, IShapeBuilder, IBuilder {
    
            var text: String? = null
    
            var color: Int = 0
    
            var borderThickness: Int = 0
    
            var borderColor: Int = 0
    
            var width: Int = 0
    
            var height: Int = 0
    
            var font: Typeface? = null
    
            var shape: RectShape? = null
    
            var textColor: Int = 0
    
            var fontSize: Int = 0
    
            var isBold: Boolean = false
    
            var toUpperCase: Boolean = false
    
            var radius: Float = 0.toFloat()
    
            init {
                text = ""
                color = Color.GRAY
                textColor = Color.WHITE
                borderThickness = 0
                borderColor = 0
                width = -1
                height = -1
                shape = RectShape()
                font = Typeface.create("sans-serif-light", Typeface.NORMAL)
                fontSize = -1
                isBold = false
                toUpperCase = false
            }
    
            override fun width(width: Int): IConfigBuilder {
                this.width = width
                return this
            }
    
            override fun height(height: Int): IConfigBuilder {
                this.height = height
                return this
            }
    
            override fun textColor(color: Int): IConfigBuilder {
                this.textColor = color
                return this
            }
    
            override fun withBorder(thickness: Int): IConfigBuilder {
                this.borderThickness = thickness
                return this
            }
    
            override fun borderColor(color: Int): IConfigBuilder {
                this.borderColor= borderColor
                return this
            }
    
            override fun useFont(font: Typeface): IConfigBuilder {
                this.font = font
                return this
            }
    
            override fun fontSize(size: Int): IConfigBuilder {
                this.fontSize = size
                return this
            }
    
            override fun bold(): IConfigBuilder {
                this.isBold = true
                return this
            }
    
            override fun toUpperCase(): IConfigBuilder {
                this.toUpperCase = true
                return this
            }
    
            override fun beginConfig(): IConfigBuilder {
                return this
            }
    
            override fun endConfig(): IShapeBuilder {
                return this
            }
    
            override fun rect(): IBuilder {
                this.shape = RectShape()
                return this
            }
    
            override fun round(): IBuilder {
                this.shape = OvalShape()
                return this
            }
    
            override fun roundRect(radius: Int): IBuilder {
                this.radius = radius.toFloat()
                val radii = floatArrayOf(radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat(), radius.toFloat())
                this.shape = RoundRectShape(radii, null, null)
                return this
            }
    
            override fun buildRect(text: String, color: Int): TextDrawable {
                rect()
                return build(text, color)
            }
    
            override fun buildRoundRect(text: String, color: Int, radius: Int): TextDrawable {
                roundRect(radius)
                return build(text, color)
            }
    
            override fun buildRound(text: String, color: Int): TextDrawable {
                round()
                return build(text, color)
            }
    
            override fun build(text: String, color: Int): TextDrawable {
                this.color = color
                this.text = text
                return TextDrawable(this)
            }
        }
    
        interface IConfigBuilder {
            fun width(width: Int): IConfigBuilder
    
            fun height(height: Int): IConfigBuilder
    
            fun textColor(color: Int): IConfigBuilder
    
            fun withBorder(thickness: Int): IConfigBuilder
    
            fun borderColor(color: Int): IConfigBuilder
    
            fun useFont(font: Typeface): IConfigBuilder
    
            fun fontSize(size: Int): IConfigBuilder
    
            fun bold(): IConfigBuilder
    
            fun toUpperCase(): IConfigBuilder
    
            fun endConfig(): IShapeBuilder
        }
    
        interface IBuilder {
    
            fun build(text: String, color: Int): TextDrawable
        }
    
        interface IShapeBuilder {
    
            fun beginConfig(): IConfigBuilder
    
            fun rect(): IBuilder
    
            fun round(): IBuilder
    
            fun roundRect(radius: Int): IBuilder
    
            fun buildRect(text: String, color: Int): TextDrawable
    
            fun buildRoundRect(text: String, color: Int, radius: Int): TextDrawable
    
            fun buildRound(text: String, color: Int): TextDrawable
        }
    
        companion object {
            private val SHADE_FACTOR = 0.9f
    
            fun builder(): IShapeBuilder {
                return Builder()
            }
        }
    }
    

    RecyclerViewClickListener.kt

    interface RecyclerViewClickListener {
        fun onNormalItemClicked(adapterPosition: Int)
    
        fun onNumberedItemClick(adapterPosition: Int)
    }
    

    OverlapImageModel.kt

    class OverlapImageModel {
        var imageUrl: String? = null
    }
    

    row_image.xml

    
    
    
        
    
    

提交回复
热议问题