android-自定义TextView在文字内容末尾添加图片icon、可以添加间距

样式示意图

样式示意图

自定义属性 style.xml

    <declare-styleable name="IconLabelTextView">
        <attr name="iconSrc" format="reference"/>
        <attr name="iconPaddingStart" format="dimension"/>
        <attr name="iconPaddingTop" format="dimension"/>
        <attr name="iconPaddingBottom" format="dimension"/>
    </declare-styleable>

自定义View-IconLabelTextView代码片段

import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import com.foreo.common.utils.DensityUtils
import com.xyz.R

class IconLabelTextView : AppCompatTextView {

    private var icon: Drawable? = null
    private var iconPaddingStart: Int = 0
    private var iconPaddingTop: Int = 0
    private var iconPaddingBottom: Int = 0

    constructor(context: Context) : super(context) {
        init(null)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init(attrs)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        init(attrs)
    }

    private fun init(attrs: AttributeSet?) {
        val a = context.obtainStyledAttributes(attrs, R.styleable.IconLabelTextView)
        icon = a.getDrawable(R.styleable.IconLabelTextView_iconSrc)
        iconPaddingStart = a.getDimensionPixelSize(R.styleable.IconLabelTextView_iconPaddingStart, 0)
        iconPaddingTop = a.getDimensionPixelSize(R.styleable.IconLabelTextView_iconPaddingTop, 0)
        iconPaddingBottom = a.getDimensionPixelSize(R.styleable.IconLabelTextView_iconPaddingBottom, 0)
        a.recycle()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas?.let { canvas ->
            val textPaint: TextPaint = paint
            val lineHeight = textPaint.descent() - textPaint.ascent()
            val lineCount = layout.lineCount
            val paddingTop = paddingTop.toFloat()
            val availableWidth = width - paddingLeft - paddingRight - DensityUtils.dp2px(30)

            val layout = layout ?: return@let

            for (i in 0 until lineCount) {
                val lineStart = layout.getLineStart(i)
                val lineEnd = layout.getLineEnd(i)
                val lineText = text.subSequence(lineStart, lineEnd).toString()

                if (i == lineCount - 1 && layout.getLineWidth(i) >= availableWidth) {
                    // last line with maxLines and text filled completely, adjust text to fit icon
                    var adjustedText = lineText
                    var textWidth = textPaint.measureText(lineText)
                    val iconWidth = icon?.intrinsicWidth ?: 0

                    while (textWidth + iconWidth + iconPaddingStart > availableWidth) {
                        adjustedText = adjustedText.substring(0, adjustedText.length - 1)
                        textWidth = textPaint.measureText(adjustedText)
                    }
                    if (!adjustedText.isNullOrBlank() && lineText != adjustedText) {
                        val splitIndex = text.indexOf(adjustedText) + adjustedText.length
                        text?.substring(0, splitIndex)?.let { text = "$it..." }
                        return
                    }

                    if (adjustedText.isNotEmpty()) {
                        val staticLayout = StaticLayout(
                            adjustedText,
                            textPaint,
                            availableWidth.toInt(),
                            Layout.Alignment.ALIGN_NORMAL,
                            1f,
                            0f,
                            false
                        )
                        val iconY =
                            paddingTop + (lineHeight * i) + (lineHeight - (icon?.intrinsicHeight
                                ?: 0)) / 2 + iconPaddingTop - iconPaddingBottom
                        val iconX = paddingLeft + staticLayout.width + iconPaddingStart
                        icon?.setBounds(
                            iconX.toInt(),
                            iconY.toInt(),
                            (iconX + iconWidth).toInt(),
                            (iconY + (icon?.intrinsicHeight ?: 0)).toInt()
                        )
                        icon?.draw(canvas)
                    }
                } else if (i == lineCount - 1 && lineEnd <= text.length) {
                    // last line, add icon
                    icon?.let {
                        val textWidth = textPaint.measureText(lineText)
                        val iconY =
                            paddingTop + (lineHeight * i) + (lineHeight - it.intrinsicHeight) / 2 + iconPaddingTop - iconPaddingBottom
                        val iconX = paddingLeft + textWidth + iconPaddingStart
                        it.setBounds(
                            iconX.toInt(),
                            iconY.toInt(),
                            (iconX + it.intrinsicWidth).toInt(),
                            (iconY + it.intrinsicHeight).toInt()
                        )
                        it.draw(canvas)
                    }
                }
            }
        }
    }

    fun setIcon(icon: Drawable?, paddingStart: Int, paddingTop: Int, paddingBottom: Int) {
        this.icon = icon
        this.iconPaddingStart = paddingStart
        this.iconPaddingTop = paddingTop
        this.iconPaddingBottom = paddingBottom
        invalidate()
    }
}

xml中使用

  <com.xyz.IconLabelTextView
		android:id="@+id/productVariation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="2"
        android:textSize="12sp"
        app:iconPaddingBottom="0dp"
        app:iconPaddingStart="5dp"
        app:iconPaddingTop="3dp"
        app:iconSrc="@drawable/ic_arrow_down_cart"
        tools:text="Normal Skin" />

代码中使用

productVariation.setIcon(getDrawable(R.drawable.ic_arrow_down_cart),10,0,0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/525641.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PKI:构建数字安全基石的关键技术

在数字化时代&#xff0c;网络安全已成为我们日常生活和工作的重要组成部分。为了确保数据的完整性、机密性和身份的真实性&#xff0c;公钥基础设施&#xff08;Public Key Infrastructure&#xff0c;简称PKI&#xff09;技术应运而生&#xff0c;为构建数字安全基石提供了重…

无人机控制框架的设计

无人机控制框架的设计主要包括以下几个模块&#xff1a;传感器模块、控制模块、通信模块和执行器模块。 传感器模块&#xff1a;负责获取无人机当前的状态信息&#xff0c;包括位置、姿态、速度等。常用的传感器包括GPS、陀螺仪、加速度计、气压计等。 控制模块&#xff1a;根…

Mysql底层原理二:Buffer Pool

1.数据区 就是描述信息缓存页这块&#xff0c;用来存放从磁盘加载的数据页&#xff08;看上图 索引页和数据页是分开的&#xff09; 2. free链表 用来标识数据区哪些数据页是可用的 3. flush链表 update的时候&#xff0c;如果数据在数据区可以找到&#xff0c;那就直接内…

Novel Influence Maximization Algorithm for Social Network Behavior Management

Abstract: 通过影响力最大化的过程来识别对社交网络中的产品采用或信息利用做出重大贡献的用户。社交网络的指数增长给这些网络的分析带来了一些挑战。现有文献非常重视对结构属性进行建模&#xff0c;而忽略了用户与其社会行为之间的关系。对于社会行为&#xff0c;本文将影响…

基于Java+SpringBoot+vue3+uniapp点餐/外卖管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

第九届蓝桥杯大赛个人赛省赛(软件类)真题C 语言 A 组-航班时间

#include<iostream> using namespace std;int getTime(){int h1, h2, m1, m2, s1, s2, d 0;//d一定初始化为0&#xff0c;以正确处理不跨天的情况 scanf("%d:%d:%d %d:%d:%d (%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);return d …

使用高德微信小程序插件实现精准获取打卡位置

由于微信小程序的 getFuzzyLocation 误差太大 不得不改用高德微信sdk 使用方法&#xff1a; 一、下载 sdk 相关下载-微信小程序插件 | 高德地图API 二、引入 sdk //引入 var amapFile require(../../libs/amap-wx.js); Page({onLoad: function() {var that this;va…

基于springboot+vue+Mysql的滴答拍摄影项目

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

组合数(费马小定理, 快速幂)

给定 n 组询问&#xff0c;每组询问给定两个整数 a&#xff0c;b&#xff0c;请你输出 Cbamod(1097)的值。 输入格式 第一行包含整数 n。 接下来 n 行&#xff0c;每行包含一组 a 和 b。 输出格式 共 n 行&#xff0c;每行输出一个询问的解。 数据范围 1≤n≤10000, 1≤…

战争中的AI应用:道德、伦理与技术的交织

AI在战争中的应用是一个极具争议和复杂的话题&#xff0c;无法简单地回答是好还是坏。其影响取决于多个因素&#xff0c;包括使用方式、目的、伦理框架以及技术本身的发展水平。 一方面&#xff0c;AI在战争中具有潜在的积极作用。它可以提高军事行动的效率和精确性&#xff0c…

持续交付工具Argo CD的部署使用

Background CI/CD&#xff08;Continuous Integration/Continuous Deployment&#xff09;是一种软件开发流程&#xff0c;旨在通过自动化和持续集成的方式提高软件交付的效率和质量。它包括持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;两个主要阶…

自然语言处理技术(Natural Language Processing)知识点

自然语言处理知识点 自然语言处理1. word2vec是什么2. 常用的NLP工具和软件3. 朴素贝叶斯分类器4. BiLSTM-CRF模型怎么去实现5. Bert模型实现NER6. 命名实体识别任务中&#xff0c;怎么去处理数据分布不均的问题&#xff1f;7. 用户问题检索相关文本时&#xff0c;具体都用了哪…

Mac下用adb命令安装apk到android设备笔记

查询了些资料记录备用。以下是在Mac上使用命令行安装APK文件的步骤&#xff1a; 1. 下载并安装ADB&#xff1a; 如果您的Mac上没有安装ADB&#xff0c;请从官方的Android开发者网站下载Android SDK Platform Tools&#xff1a;Android SDK Platform Tools。将下载的ZIP文件解…

KylinOS银河麒麟安装部署AI服务

KylinOS银河麒麟安装部署AI服务&#xff08;CPU版本&#xff09; 查看操作系统 [jnapp8160fcc7cf1b ~]$ nkvers ############## Kylin Linux Version ################# Release: Kylin Linux Advanced Server release V10 (Lance)Kernel: 6.2.0-36-genericBuild: Kylin Linux…

数据挖掘及其近年来研究热点介绍

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

什么是mka音频格式?mp3与mka音频的区别 如何把mp3转成mka格式?

一&#xff0c;什么是mka音频格式 mka音频是一种音频文件格式&#xff0c;它是Matroska多媒体容器格式的一种变体&#xff0c;专门用于存储音频数据。mka文件通常包含压缩的音频流&#xff0c;如MP3、AAC或FLAC等&#xff0c;以及其他可能的元数据&#xff0c;如专辑封面、艺术…

24 个Intellij IDEA好用插件

24 个Intellij IDEA好用插件 一. 安装插件 Codota 代码智能提示插件 只要打出首字母就能联想出一整条语句&#xff0c;这也太智能了&#xff0c;还显示了每条语句使用频率。 原因是它学习了我的项目代码&#xff0c;总结出了我的代码偏好。 Key Promoter X 快捷键提示插件 …

基于ARM内核的智能手环(day7)

RTC&#xff08;实时时钟&#xff09; 什么是RTC&#xff1f; RTC是指实时时钟&#xff08;Real-Time Clock&#xff09;&#xff0c;是一种能够持续跟踪时间的计时器&#xff0c;即使在设备断电的情况下也能保持时间的准确性。它通常用于需要准确时间记录的应用&#xff0c;…

[每日算法 - 阿里机试] leetcode739. 每日温度

入口 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/daily-temperatures/descr…

深度学习理论基础(七)Transformer编码器和解码器

学习目录&#xff1a; 深度学习理论基础&#xff08;一&#xff09;Python及Torch基础篇 深度学习理论基础&#xff08;二&#xff09;深度神经网络DNN 深度学习理论基础&#xff08;三&#xff09;封装数据集及手写数字识别 深度学习理论基础&#xff08;四&#xff09;Parse…