草庐IT

java - 水平放置圆形图像以显示用户个人资料图片

coder 2023-12-26 原文

我需要显示所有参加指定 Activity 的用户个人资料图片,它应该在水平圆形图像中一张接一张,在 5 张图像之后。它应该显示剩余的用户总数。我需要 java 和 xml 文件。这些个人资料图像将来自数据库。请给我建议任何图书馆或一种方法

最佳答案

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>

关于java - 水平放置圆形图像以显示用户个人资料图片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52178656/

有关java - 水平放置圆形图像以显示用户个人资料图片的更多相关文章

  1. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  4. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  5. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  6. ruby-on-rails - link_to 不显示任何 rails - 2

    我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article

  7. ruby-on-rails - 使用 Rmagick 或 ImageMagick 在背景上放置标题 - 2

    我有一张背景图片,我想在其中添加一个文本框。我想弄清楚如何将标题放置在其顶部的正确位置。(我使用标题是因为我需要自动换行功能)。现在,我只能让文本显示在左上角,但我需要能够手动定位它的开始位置。require'RMagick'require'Pry'includeMagicktext="Loremipsumdolorsitamet"img=ImageList.new('template001.jpg')img 最佳答案 这是使用convert的ImageMagick命令行的答案。如果你想在Rmagick中使用这个方法,你必须自己移植

  8. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  9. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  10. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

随机推荐