Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Horizontally of circular images to show user profile picture

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 should show the remaining users total count. I need both java and xml file. These profile images will be from database. Please suggest me any library or a way to do it

I need like this

like image 537
Tharun Eniyan Avatar asked Sep 05 '18 06:09

Tharun Eniyan


2 Answers

enter image description here

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<OverlapImageModel> {
        val mArrayList = ArrayList<OverlapImageModel>()

        //-----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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:orientation="vertical"
    tools:context=".activities.OverlapImageViewActivity">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingEnd="5dp"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        tools:listitem="@layout/row_image" />

</LinearLayout>

OverLapRecyclerViewAdapter.kt

class OverlapRecyclerViewAdapter(private var mContext: Context, private var recyclerViewClickListener: RecyclerViewClickListener
                                 , private val overlapLimit: Int) : RecyclerView.Adapter<OverlapRecyclerViewAdapter.CustomViewHolder>() {

    private val TAG = OverlapRecyclerViewAdapter::class.java.simpleName

    //----array list to be shown
    private var mImageList = ArrayList<OverlapImageModel>()

    //----array list to be shown after expansion
    private var mImageExpandedList = ArrayList<OverlapImageModel>()

    //----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<OverlapImageModel>) {
        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<OverlapImageModel>) {
        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

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="@dimen/image_size"
    android:layout_height="@dimen/image_size"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_gravity="center"
    android:animateLayoutChanges="true">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/imageView"
        app:civ_border_color="#ffffff"
        app:civ_border_width="2dp"
        android:layout_width="@dimen/image_size"
        android:layout_height="@dimen/image_size"
        android:layout_centerInParent="true"
        tools:src="@mipmap/ic_launcher" />
</RelativeLayout>
like image 150
Malik Motani Avatar answered Sep 22 '22 11:09

Malik Motani


enter image description here

Try this here is the working code for java

RecyclerViewActivity

public class RecyclerViewActivity extends AppCompatActivity {


    private  final Integer[] IMAGES = {R.drawable.nilesh, R.drawable.nilesh, R.drawable.nilesh, R.drawable.nilesh,
            R.drawable.nilesh, R.drawable.nilesh, R.drawable.nilesh, R.drawable.nilesh};
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();

    RecyclerView myRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);

        Collections.addAll(arrayList, IMAGES);

        myRecyclerView=findViewById(R.id.myRecyclerView);
        myRecyclerView.setLayoutManager(new LinearLayoutManager(this,
                LinearLayoutManager.HORIZONTAL,false));
        myRecyclerView.addItemDecoration(new OverlapDecoration());
        myRecyclerView.setHasFixedSize(true);
        myRecyclerView.setAdapter(new DataAdapter(this,arrayList));


    }

    public class OverlapDecoration extends RecyclerView.ItemDecoration {

        private final static int vertOverlap = -40;

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            final int itemPosition = parent.getChildAdapterPosition(view);


            outRect.set(0, 0, vertOverlap, 0);


        }
    }
}

activity_recycler_view

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/colorBackgroundFloating"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/myRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="250dp"
         />


</LinearLayout>

DataAdapter

public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {

    private Context context;
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();

    public DataAdapter(Context context, ArrayList<Integer> imagesArray) {
        this.context = context;
        arrayList = imagesArray;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View imageLayout = LayoutInflater.from(context).inflate(R.layout.aa, parent, false);
        return new ViewHolder(imageLayout);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {

        holder.imageView.setImageResource(arrayList.get(position));

        if (position == 3) {
            holder.relativeLayout.setVisibility(View.VISIBLE);
            holder.tvCount.setText(String.valueOf(arrayList.size()-4));
        }else {
            holder.relativeLayout.setVisibility(View.GONE);
        }
    }

    @Override
    public int getItemCount() {
        return 4;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        RelativeLayout relativeLayout;
        TextView tvCount;
        CircleImageView imageView;

        public ViewHolder(View itemView) {
            super(itemView);

            relativeLayout = itemView.findViewById(R.id.relative);
            tvCount = itemView.findViewById(R.id.tvCount);
            imageView = itemView
                    .findViewById(R.id.profile_image);


        }
    }
}

layout.aa

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">


    <de.hdodenhof.circleimageview.CircleImageView xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/profile_image"
        android:layout_width="96dp"
        android:layout_height="96dp"
        android:src="@drawable/kid"
        app:civ_border_color="#FF000000"
        app:civ_border_width="2dp" />

    <RelativeLayout
        android:id="@+id/relative"
        android:visibility="gone"
        android:layout_marginLeft="-40dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">


        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/imageCircleImageView"
            android:layout_width="96dp"
            android:layout_height="96dp"
            android:src="#919191"
            app:civ_border_color="#FF000000"
            app:civ_border_width="2dp"  />

        <TextView
            android:id="@+id/tvCount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@id/imageCircleImageView"
            android:layout_alignEnd="@id/imageCircleImageView"
            android:layout_alignStart="@id/imageCircleImageView"
            android:layout_alignTop="@id/imageCircleImageView"
            android:layout_gravity="center"
            android:gravity="center"
            android:padding="10dp"
            android:text=""
            android:textColor="#FFFFFF" />

    </RelativeLayout>

</LinearLayout>
like image 36
AskNilesh Avatar answered Sep 21 '22 11:09

AskNilesh