美文网首页
自定义View基础(一)

自定义View基础(一)

作者: 野火友烧不尽 | 来源:发表于2018-08-05 17:37 被阅读0次

自定义View有两种:

  • 自定义View,如:TextView,这些只有内容没有子View的;
  • 自定义ViewGroup,比较难,如:LinearLayout,有子View;
    自定义View基本流程:measure->layout->draw,这些调度方法,onMeasure->onLayout->onDraw

首先总结一下的关键点:

  • 自定义绘制的方式是重写绘制方法,绘制主体的内容,其中最常用的是 onDraw()
  • 绘制的关键是 Canvas 的使用 ;
    Canvas 的绘制类方法: drawXXX() (关键参数:Paint)
    Canvas 的辅助类方法:范围裁切和几何变换
  • 可以使用不同的绘制方法来控制遮盖关系;

绘制的顺序:
1、背景(drawBackground())
2、主体(onDraw())
3、子 View(dispatchDraw())
4、滑动边缘渐变和滑动条前景(onDrawForeground())

今天只讲自定义View的一些与绘制相关的API和细节,上效果图:

U@U}OD$U{SK_PX24IO3ASGJ.png

这里面主要就是:画圆、阴影画文本下面就是主要代码:

class CustomView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {

private val mPaint = Paint()
private val mTextPaint = TextPaint()
private var mTextNumber: String = "00000步"
private var text = "我是文字,hahahhah"


init {
    mPaint.style = Paint.Style.STROKE//设置绘制模式
    mPaint.strokeWidth = dp2px(5).toFloat()//设置线条宽度
    mPaint.color = Color.GREEN//设置颜色
    mPaint.isAntiAlias = true//设置抗锯齿开关

    /*
        setShadowLayer只有文字绘制阴影支持硬件加速,其它都不支持硬件加速
     */
    setLayerType(LAYER_TYPE_SOFTWARE, null) //关闭硬件加速
    mPaint.setShadowLayer(10f, 2f, 2f, Color.BLACK) // 不能与setMaskFilter同时使用
//        val blurMaskFilter = BlurMaskFilter(10f, BlurMaskFilter.Blur.NORMAL)
//        mPaint.maskFilter = blurMaskFilter
}

var mDefaultWidth: Int = 400
var mDefaultHeight: Int = 300

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    mDefaultWidth = resolveSize(mDefaultWidth, widthMeasureSpec)
    mDefaultHeight = resolveSize(mDefaultHeight, heightMeasureSpec)
    setMeasuredDimension(mDefaultWidth, mDefaultHeight)
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    canvas.drawColor(Color.GRAY)

    canvas.save()//及时保存canvas之前的配置
    canvas.translate(mDefaultWidth / 2f, mDefaultHeight / 2f)//将坐标移动至view的中心,方便绘制
    val radius = Math.min(mDefaultWidth / 2f, mDefaultHeight / 2f) - mPaint.strokeWidth
    canvas.drawCircle(0f, 0f, radius, mPaint)
    canvas.restore()//恢复save之前的配置

    mTextPaint.isAntiAlias = true//抗锯齿
    mTextPaint.textSize = 25f
    mTextPaint.color = Color.RED
    val textWidth = mTextPaint.measureText(text)//测量文本的宽度
    val textHeight = -mTextPaint.ascent() + mTextPaint.descent()//得到文本的高度
    canvas.save()
    canvas.translate(mDefaultWidth / 2f, mDefaultHeight / 2f)
    canvas.drawText(text, 0, text.length, -textWidth / 2, textHeight / 2, mTextPaint)
    canvas.restore()


    canvas.save()
    mTextPaint.textSize = 30f
    mTextPaint.color = Color.WHITE
    //通过Rect获取文本宽度和高度
    val rect = Rect()
    mTextPaint.getTextBounds(mTextNumber, 0, mTextNumber.length, rect)
    val textNumWidth = rect.width().toFloat()
    val textNumHeight = rect.height().toFloat()
    canvas.translate(mDefaultWidth / 2f, mDefaultHeight / 2f)
    canvas.drawText(mTextNumber, 0, mTextNumber.length, -textNumWidth / 2, (textNumHeight / 2) - (textHeight + 10), mTextPaint)
    canvas.restore()

}

fun updateNumText(text: String) {
    mTextNumber = "${text}步"
    postInvalidate()
}

fun updateText(text: String) {
    this.text = "${text}步"
    postInvalidate()
}

}
总结
  • canvas.save()和canvas.restore()

及时保存canvas之前的配置,也就是后面会用canvas.restore()恢复里其最近的配置,save()是由返回值的,官方说了,如果你多欧茨调用save,但是想要恢复指定save的配置,可以使用下面的方式,所以就有了:canvas.restoreToCount(count)

 int count = canvas.save();
 canvas.restoreToCount(count);
  • canvas.translate(cx,cy)

将view的坐标原定移动至cx,cy;

Canvas的这类方法,我想大家都知道View的内容都是canvas画出来的,所以canvas的坐标系也就是View的坐标系,默认原点在左上角,而如果我们想改变View的坐标系,那么就需要通过Canvas,其实操作的都是Matrix,即矩阵,矩阵就和坐标系相关,所以我这里暂时理解为操作的是View的坐标系,这里就不详细将Matrix。
所以这类方法还有几个:canvas.rotate(degrees, px, py)(旋转),scale(sx, sy, px, float py)(缩放),skew(sx, sy)(错切),这些操作都会影响Matrix即坐标系,而View的translationX这些只是对View在ayout中的偏移位置。
不知道这样理解有没有偏差,请指正。
所有的内容都有注释了,下周讲一下,蚂蚁积分的信用控件,

相关文章

网友评论

      本文标题:自定义View基础(一)

      本文链接:https://www.haomeiwen.com/subject/gxgbvftx.html