样式示意图
自定义属性 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 = paintval lineHeight = textPaint. descent ( ) - textPaint. ascent ( ) val lineCount = layout. lineCountval 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) { var adjustedText = lineTextvar 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. lengthtext?. 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 - iconPaddingBottomval iconX = paddingLeft + staticLayout. width + iconPaddingStarticon?. setBounds ( iconX. toInt ( ) , iconY. toInt ( ) , ( iconX + iconWidth) . toInt ( ) , ( iconY + ( icon?. intrinsicHeight ? : 0 ) ) . toInt ( ) ) icon?. draw ( canvas) } } else if ( i == lineCount - 1 && lineEnd <= text. length) { icon?. let { val textWidth = textPaint. measureText ( lineText) val iconY = paddingTop + ( lineHeight * i) + ( lineHeight - it. intrinsicHeight) / 2 + iconPaddingTop - iconPaddingBottomval iconX = paddingLeft + textWidth + iconPaddingStartit. 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 = iconthis . iconPaddingStart = paddingStartthis . iconPaddingTop = paddingTopthis . iconPaddingBottom = paddingBottominvalidate ( ) }
}
xml中使用
< com. xyz. IconLabelTextViewandroid : 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 )