一让Padding值有效
前边我们已经绘制了两个自定义控件,细心的同学可能会发现问题:你自定义View设置padding值是无效的。但是margin是有效的。
android:layout_margin=""
android:padding=""观察上边的代码:
margin是以layout开头的,所以它是属于父类布局处理的事情,而父类布局我们使用的是系统的布局,系统已经帮我们处理了,所以它是有效的。
padding没有以layout开头,它属于控件自身的属性,需要我们自己去处理,如果没有处理,当然是无效属性。
由此可知:
自定义View时候需要开发者处理padding值
自定义ViewGroup时候需要开发者处理margin和padding值
这篇我们只说自定义View处理padding的事情,而自定义ViewGroup的问题处理等讲到自定义ViewGroup的时候再去讲怎么处理。
怎么处理呢?
很简单,只需要在计算的时候获取内边距的值,然后再计算的时候考虑进去即可。
怎么获取这个值呢?
在自定义View中通过get方法直接获取即可,对应的Kotlin中直接使用常量即可
paddingLeft
paddingRight
paddingTop
paddingBottom当然我们再自定义View,自己使用的时候一般都不去考虑这个四个属性(我反正是这样),但是自定义View给别人用的时候,我们一般要考虑四个属性。当然,为了规范开发,考虑上去这四个值没有什么错。(之前两个自定义View我就不做修改,知道有这个问题即可)
效果图:
原理图:
对应代码:
package MyViews
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.os.Build
import android.support.annotation.RequiresApi
import android.util.AttributeSet
import android.util.Log
import android.view.View
/**
* Created by Administrator on 2018/7/10.
* 自定义水平进度条,主要学习padding设置的用法
*/
class HorizontalProgress : View {
//控件默认的宽
val defult_Widht: Float
//控件默认高度
val defult_Hdight: Float
//topRect高度
val topRectHeight = DisplayUtils.dip2px(context, 14F)
//topRect宽度
val topRectWidth = DisplayUtils.dip2px(context, 24F)
//三角形的宽度高度
val triangle_Height_width = DisplayUtils.dip2px(context, 6F)
//进度条和三角形的间隔
val progressToTeiangle = DisplayUtils.dip2px(context, 6F)
//进度条线线的宽度
val progressLineWidth = DisplayUtils.dip2px(context, 4F)
//进度条和控件底部间隔
val progressToBottom = DisplayUtils.dip2px(context, 6F)
//画背景的画笔
private lateinit var bg_Paint: Paint
//画头部矩形的画笔
private lateinit var top_Paint: Paint
//顶部文字的画笔
private lateinit var text_Paint: Paint
//画进度条的画笔
private lateinit var progress_Paint: Paint
//当前进度
private var progress = 0
set(value) {
field = value
invalidate()
}
//结束进度,
var endProgress = 0
//构造方法
constructor(context: Context?) : this(context, null)
//构造方法
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
//构造方法
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : this(context, attrs, defStyleAttr, 0)
//构造方法
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
//控件的高度 = 上边巨型的高度+三角形的高度+三角形和进度条的间隔+进度条的高度+进度条到底部的高度
defult_Hdight = topRectHeight + triangle_Height_width + progressToTeiangle + progressLineWidth + progressToBottom
defult_Widht = DisplayUtils.getDisplayWidth(context) - topRectWidth
initPaint()
}
private fun initPaint() {
//创建画背景圆的画笔
bg_Paint = Paint(Paint.ANTI_ALIAS_FLAG)
//设置画线模式
bg_Paint.style = Paint.Style.STROKE
//设置画线的宽度
bg_Paint.strokeWidth = progressLineWidth
//设置线的颜色
bg_Paint.color = Color.parseColor("#cccccc")
//创建画背景的画笔
top_Paint = Paint(Paint.ANTI_ALIAS_FLAG)
//设置画笔颜色
top_Paint.color = Color.parseColor("#FFAA00")
//创建文字画笔
text_Paint = Paint(Paint.ANTI_ALIAS_FLAG)
//设置画笔颜色
text_Paint.color = Color.WHITE
//计算文字开始大小
text_Paint.textSize = DisplayUtils.sp2px(context, 8F).toFloat()
//设置中心位置
text_Paint.textAlign = Paint.Align.CENTER
progress_Paint = Paint(Paint.ANTI_ALIAS_FLAG)
//设置画线模式
progress_Paint.style = Paint.Style.STROKE
//设置画线的宽度
progress_Paint.strokeWidth = progressLineWidth
//设置线的颜色
progress_Paint.color = Color.parseColor("#FFAA00")
}
//测量
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(resolveSize(defult_Widht.toInt(), widthMeasureSpec), resolveSize(defult_Hdight.toInt() + paddingBottom + paddingTop, heightMeasureSpec))
}
//绘制
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onDraw(canvas: Canvas) {
drawBgLine(canvas)
drawTopRect(canvas)
drawTriangle(canvas)
drawTopText(canvas)
drawProgressLine(canvas)
}
//画背景线,这里考虑了Padding值
private fun drawBgLine(canvas: Canvas) {
//画线需要算出起始点和终止点
canvas.drawLine(0F + paddingLeft+topRectWidth/2, topRectHeight + triangle_Height_width + progressToTeiangle + paddingTop,
defult_Widht - paddingRight+topRectWidth/2, topRectHeight + triangle_Height_width + progressToTeiangle + paddingTop,
bg_Paint)
}
//画顶部矩形
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun drawTopRect(canvas: Canvas) {
var newLine = (defult_Widht - paddingRight - paddingLeft) * progress / 100 - topRectWidth / 2
canvas.drawRoundRect(0F + paddingLeft + newLine+topRectWidth/2, 0F + paddingTop, topRectWidth + paddingLeft + newLine+topRectWidth/2, topRectHeight + paddingTop, 2F, 2F, top_Paint)
}
//绘制三角形
fun drawTriangle(canvas: Canvas) {
var newLine = (defult_Widht.toFloat() - paddingRight - paddingLeft) * progress / 100 - topRectWidth / 2
var path = Path()
//需要计算三角形的三个点的坐标
var startX = (topRectWidth - triangle_Height_width) / 2 + paddingLeft + newLine+topRectWidth/2
var startY = topRectHeight - 2 + paddingTop
var twoX = (topRectWidth + triangle_Height_width) / 2 + paddingLeft + newLine+topRectWidth/2
var twoY = topRectHeight - 2 + paddingTop
var endX = topRectWidth / 2 + paddingLeft + newLine+topRectWidth/2
var endY = topRectHeight + triangle_Height_width + paddingTop
path.moveTo(startX, startY)
path.lineTo(twoX, twoY)
path.lineTo(endX, endY)
//封闭缺口
path.close()
canvas.drawPath(path, top_Paint)
}
//绘制顶部文字
private fun drawTopText(canvas: Canvas) {
var newLine = (defult_Widht.toFloat() - paddingRight - paddingLeft) * progress / 100 - topRectWidth / 2
//需要算出来文字的x以及baseLine
var x = topRectWidth / 2 + paddingLeft + newLine+topRectWidth/2
val fontMetrics = text_Paint.getFontMetrics()
var baseline = topRectHeight / 2 + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom + paddingTop
canvas.drawText("$progress%", x, baseline, text_Paint)
}
//绘制进度走的值
fun drawProgressLine(canvas: Canvas) {
//需要动态去设置这个终点的值,所以需要计算
//因为这里是直线,所以除了用DashPathEffect之外,还可以通过改变终点的坐标去执行动画,但是如果是曲线,就只有用DashPathEffect去绘制动画
var newLine = (defult_Widht - paddingRight - paddingLeft) * progress / 100
Log.e("rrrrrrrr", newLine.toString())
//画线需要算出起始点和终止点
canvas.drawLine(0F + paddingLeft+topRectWidth/2, topRectHeight + triangle_Height_width + progressToTeiangle + paddingTop,
newLine + paddingLeft+topRectWidth/2, topRectHeight + triangle_Height_width + progressToTeiangle + paddingTop,
progress_Paint)
}
//开启动画
fun start() {
val ofInt = ObjectAnimator.ofInt(this, "progress", 0, endProgress)
ofInt.duration = 1000
ofInt.start()
}
}