建立自己的王国:Android 自定义封装View(3)
2021-08-20 本文已影响0人
努尔江
效果图:
effect0.jpg
产品需求:
制作产品标签卡。限定高度,自适用宽度(Max限制). 两种类型,产品或其他。产品的时候上面是产品名,下面是价格。其他只有一行文案。左边的图片也不同(总共8种不同类型)。
实现思路(伪代码):
1.先画出左边的ICON下面的圆形。
canvas.drawCircle(x ,y)
- 圆内画出ICON。
canvas.drawBitmap(bitmap, x, y, paint)
3.以圆坐标加圆半径的距离开始画三角形。
path.moveTo(x,y)
path.lineTo(x,y)
path.lineTo(x,y)
path.close()
canvas.drawPath(path,paint)
4.从三角形的右边坐标画圆角四边形。
canvas.drawRoundRect(react,radius,radius,paint)
- 画出文字。
canvas.drawText(text,x,y,paint)
实现
还是继承View。并且重写三个必须的构造方法和两个方法。由于产品卡数量的不确定性,也不能设置封装对象作为属性。只能通过传值到View来进行多个标签的渲染。
- 重写结构体:
class PostTagView : View {
constructor(mContext: Context) : super(mContext)
constructor(mContext: Context, attributeSet: AttributeSet) : super(mContext, attributeSet)
constructor(mContext: Context, attributeSet: AttributeSet, theme: Int) : super(
mContext,
attributeSet,
theme
)
}
- 定义使用的变量。
/**
* React 四边形坐标点
*/
var react= RectF()
/**
* M paint 画C1C1C1 为背景。
* 注:抗锯齿关闭(为了性能)
* @see Paint.isAntiAlias
*/
private lateinit var mPaint:Paint
/**
* T paint 画文案
* 抗锯齿已开。
* 颜色白色。
*/
private lateinit var tPaint:Paint
/**
* C paint 透明背景
*/
private lateinit var cPaint:Paint
/**
* Path 路径 画三角形
*/
private lateinit var path:Path
/**
* Bitmap 解析Bitmap
*/
private lateinit var bitmap: Bitmap
3.初始化变量。
/**
* Init params
* 这里会初始化一些变量。
*/
private fun initParams() {
//初始化 主要颜色
mPaint = Paint()
mPaint.isAntiAlias=false
mPaint.color = Color.parseColor("#1c1c1c")
mPaint.style = Paint.Style.FILL
//初始化 文字
tPaint= Paint()
tPaint.isAntiAlias=true
tPaint.color = Color.WHITE
tPaint.textSize=DisplayUtils.dip2px(12F).toFloat()
tPaint.typeface= Typeface.DEFAULT_BOLD
//初始化Path
path=Path()
//初始化cPaint
cPaint= Paint()
cPaint.color=Color.parseColor("#B31c1c1c")
cPaint.isAntiAlias=false
}
- 渲染
/**
* Draw other 除了产品 画其他Tag
*
* @param src 资源(R.drawable.xxx)
* @param x 初始x坐标
* @param y 初始y坐标
* @param content 文案
* @param canvas Canvas
*/
fun drawOtherTag(src:Int,x:Float,y:Float,content:String,canvas: Canvas?){
//解决文字的长度问题
var temp= if (content.length>13){
content.substring(0..13)+"..."
}else{
content
}
val drawable=AppCompatResources.getDrawable(context,src)
bitmap=drawable!!.toBitmap(DisplayUtils.dip2px(20F),DisplayUtils.dip2px(20F))
canvas?.drawCircle(x,y,DisplayUtils.dip2px( 15f).toFloat(),cPaint)
path.moveTo(x+DisplayUtils.dip2px(15F).toFloat(),y)
path.lineTo(x+DisplayUtils.dip2px(25F),y+DisplayUtils.dip2px(10F))
path.lineTo(x+DisplayUtils.dip2px(25F),y+DisplayUtils.dip2px(-10F))
path.close()
canvas?.drawPath(path,mPaint)
react= RectF(x+DisplayUtils.dip2px(25F),y-DisplayUtils.dip2px(20F),x+tPaint.measureText(temp)+DisplayUtils.dip2px(50F),y+DisplayUtils.dip2px(20F))
canvas!!.drawRoundRect(react,30F,30F,mPaint)
canvas.drawText(temp,x+DisplayUtils.dip2px(35F),y+DisplayUtils.dip2px(3F),tPaint)
canvas.drawBitmap(bitmap,x-DisplayUtils.dip2px(10F),y-DisplayUtils.dip2px(10F),null)
canvas.save()
}
注明一下:我之所以使用dp转pixel的值,是为了兼容不同设备下显示相同大小的object。Canvas的值是pixel为单位的。
最后效果图:
effects.png