First of all, look at the trilogy of custom View.
1:onMeasure method
The main purpose of this method is based on xml
android:layout_width="wrap_content"
android:layout_height="wrap_content"
The wrap_content match_parent attributes determine the size of the measurement itself.
Of course, these two values, just parent tells you, need to be measured according to this rule, if you are a bad child, then you can ignore the measurement rules, arbitrarily set a width and height, such as: setMeasured Dimension (10,000, 20,000) is so simple;
2:onLayout method
If you're a custom View, this method doesn't need to override
If you are a custom View Group, you must override it. The purpose of this method is that you decide where the child view is on the interface.
3:onDraw method
In this way, you can expand your gifted drawing function and draw whatever you want. Beautiful view comes out like this.
Friendship Tip: If you are a custom ViewGroup, you also need to call the setWillNotDraw(false) method, otherwise the onDraw method will not execute.
Don't worry, analyse a wave:
1:There are two sliding floats.
2: A track is needed. The float slides on the track.
3: The colours between floats are different
4: Progress text on the float
There are not many steps, but they can be achieved easily.
Because it's all a draw operation, the onDraw code is pasted here directly:
onDraw
override fun onDraw(canvas: Canvas) {
//canvas.drawColor(Color.parseColor("#80000000"))
paint.style = Paint.Style.FILL
paint.color = trackColor
paint.textSize = textSize
//Orbit mapping
trackRectF.set((paddingLeft + thumbRadius).toFloat(), trackTop,
measuredWidth.toFloat() - paddingRight - thumbRadius, trackTop + trackHeight)
canvas.drawRoundRect(trackRectF, trackRoundRadius.toFloat(), trackRoundRadius.toFloat(), paint)
//Calculating rectangular coordinate position of float
calcThumbValueRect()
//Drawing progress
paint.style = Paint.Style.FILL
paint.color = progressColor
progressRectF.set(minValueRectF.centerX(), trackRectF.top, maxValueRectF.centerX(), trackRectF.bottom)
canvas.drawRoundRect(progressRectF, trackRoundRadius.toFloat(), trackRoundRadius.toFloat(), paint)
//Draw float
drawThumb(canvas, minValueRectF)
drawThumb(canvas, maxValueRectF)
//Draw prompt text
drawText(canvas, minValueRectF, currentMinValue)
drawText(canvas, maxValueRectF, currentMaxValue)
}
private fun drawThumb(canvas: Canvas, rectF: RectF) {
paint.style = Paint.Style.FILL
paint.color = thumbColor
canvas.drawCircle(rectF.centerX(), rectF.centerY(), thumbRadius.toFloat(), paint)
//Drawing Float Outer Circle
paint.style = Paint.Style.STROKE
paint.strokeWidth = 2 * density
paint.color = thumbOutLineColor
canvas.drawCircle(rectF.centerX(), rectF.centerY(), thumbRadius.toFloat() - 1 * density, paint)
}
private fun drawText(canvas: Canvas, rectF: RectF, progress: Int) {
paint.style = Paint.Style.FILL_AND_STROKE
paint.color = textColor
paint.strokeWidth = 1f
val text: String = rangeListener?.getProgressText(progress) ?: "$progress%"
canvas.drawText(text,
Math.min(Math.max(0f, rectF.centerX() - textWidth(paint, text) / 2),
viewWidth - textWidth(paint, text)),
paddingTop + textHeight(paint) - paint.descent(),
paint)
}
private fun calcThumbValueRect() {
val x = (viewWidth - 2 * thumbRadius) * (currentMinValue.toFloat() / 100f) + paddingLeft
minValueRectF.set(
x,
trackTop + trackHeight / 2 - thumbRadius,
x + 2 * thumbRadius,
trackTop + trackHeight / 2 + thumbRadius
)
val x2 = (viewWidth - 2 * thumbRadius) * (currentMaxValue.toFloat() / 100f) + paddingLeft
maxValueRectF.set(
x2,
trackTop + trackHeight / 2 - thumbRadius,
x2 + 2 * thumbRadius,
trackTop + trackHeight / 2 + thumbRadius
)
}
Gesture processing:
/**Gestures are held at that point, regardless of the maximum and minimum points.*/
private var touchValue: Int = -1
private var notTouchValue: Int = -1
override fun onTouchEvent(event: MotionEvent): Boolean {
val action = MotionEventCompat.getActionMasked(event)
when (action) {
MotionEvent.ACTION_DOWN -> {
if (minValueRectF.contains(event.x, event.y)) {
touchValue = currentMinValue
notTouchValue = currentMaxValue
} else if (maxValueRectF.contains(event.x, event.y)) {
touchValue = currentMaxValue
notTouchValue = currentMinValue
} else {
touchValue = -1
notTouchValue = -1
}
}
MotionEvent.ACTION_MOVE -> {
if (touchValue >= 0) {
parent.requestDisallowInterceptTouchEvent(true)
//Put it on the spot
touchValue = ((event.x - paddingLeft - thumbRadius) / (viewWidth - 2 * thumbRadius) * 100).toInt()
touchValue = ensureValue(touchValue)
//L.e("call: onTouchEvent ->$viewWidth ${event.x} $touchValue")
if (Math.abs(touchValue - notTouchValue) >= MIN_RANGE) {
currentMinValue = Math.min(touchValue, notTouchValue)
currentMaxValue = Math.max(touchValue, notTouchValue)
postInvalidate()
rangeListener?.onRangeChange(currentMinValue, currentMaxValue)
}
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
parent.requestDisallowInterceptTouchEvent(false)
}
}
return true
}
Contact author
Please use QQ scanner to add group, small partners are waiting for you!
Pay attention to my public number and play together every day!