基本步骤
自定义View的属性
format取值类型:
| 格式类型 |
含义说明 |
reference |
资源引用,例如 @string/app_name、@drawable/icon |
string |
字符串文本,例如 "Hello" |
integer |
整数,例如 42 |
boolean |
布尔值,例如 true、false |
color |
颜色值,例如 #FF0000 或 @color/primary |
dimension |
尺寸值,例如 16dp、12sp |
float |
浮点数,例如 3.14 |
enum |
枚举值(需配合 <enum> 使用) |
flag |
位标志(可多选,需配合 <flag> 使用) |
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="titleText" format="string" /> <attr name="titleTextColor" format="color" /> <attr name="titleTextSize" format="dimension" /> <declare-styleable name="MyView"> <attr name="titleText" /> <attr name="titleTextColor" /> <attr name="titleTextSize" /> </declare-styleable> </resources>
|
在View的构造方法中获得我们自定义的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| class MyView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) {
private var mTitleText: String = ""
private var mTitleTextColor: Int = Color.BLACK
private var mTitleTextSize: Int = 0
private val mBound: Rect = Rect()
private val mPaint: Paint = Paint()
init { attrs?.let { val typedArray = context.theme.obtainStyledAttributes( it, R.styleable.MyView, defStyleAttr, 0 )
try { mTitleText = typedArray.getString(R.styleable.MyView_titleText) ?: ""
mTitleTextColor = typedArray.getColor( R.styleable.MyView_titleTextColor, Color.BLACK )
mTitleTextSize = typedArray.getDimensionPixelSize( R.styleable.MyView_titleTextSize, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16f, resources.displayMetrics ).toInt() ) } finally { typedArray.recycle() } }
mPaint.textSize = mTitleTextSize.toFloat() mPaint.color = mTitleTextColor
mPaint.getTextBounds(mTitleText, 0, mTitleText.length, mBound) } }
|
[重写onMeasure()方法](并非必要)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val widthMode = MeasureSpec.getMode(widthMeasureSpec) val widthSize = MeasureSpec.getSize(widthMeasureSpec) val heightMode = MeasureSpec.getMode(heightMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec)
var width: Int var height: Int
mPaint.textSize = mTitleTextSize.toFloat() if (mTitleText.isNotEmpty()) { mPaint.getTextBounds(mTitleText, 0, mTitleText.length, mBound) }
val textWidth = mBound.width() val textHeight = mBound.height()
width = when (widthMode) { MeasureSpec.EXACTLY -> widthSize MeasureSpec.AT_MOST -> minOf(widthSize, paddingLeft + textWidth + paddingRight) MeasureSpec.UNSPECIFIED -> paddingLeft + textWidth + paddingRight else -> paddingLeft + textWidth + paddingRight }
height = when (heightMode) { MeasureSpec.EXACTLY -> heightSize MeasureSpec.AT_MOST -> minOf(heightSize, paddingTop + textHeight + paddingBottom) MeasureSpec.UNSPECIFIED -> paddingTop + textHeight + paddingBottom else -> paddingTop + textHeight + paddingBottom } setMeasuredDimension(width, height) }
|
重写onDraw()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| override fun onDraw(canvas: Canvas) { mPaint.color = Color.YELLOW
canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), mPaint)
mPaint.color = mTitleTextColor
canvas.drawText( mTitleText, (width / 2 - mBound.width() / 2).toFloat(), (height / 2 + mBound.height() / 2).toFloat(), mPaint ) }
|
如果还需要点击事件,可以在init{}里面加上注册监听器语句
1 2 3 4
| this.setOnClickListener { postInvalidate() }
|
引入布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:custom="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:ignore="ResAuto"> <com.example.studyview.MyView android:layout_width="wrap_content" android:layout_height="wrap_content" custom:titleText="3712" android:padding="10dp" custom:titleTextColor="#ff0000" android:layout_centerInParent="true" custom:titleTextSize="40sp" />
</RelativeLayout>
|