Commit 940128af authored by 周文华's avatar 周文华

【新增】新增部分自定义控件

parent 537c148e
package com.base.scanqrclear.luma
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import com.base.scanqrclear.R
class CircleBorderView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint().apply {
isAntiAlias = true // 抗锯齿
color = context.getColor(R.color.color_fedbbb)
style = Paint.Style.STROKE
strokeWidth = dpToPx(1).toFloat() // 设置边框宽度为1dp
}
private var circleRadius: Float = 0f
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 绘制圆
circleRadius = (Math.min(width, height) - paint.strokeWidth) / 2
canvas.drawCircle(width / 2f, height / 2f, circleRadius, paint)
}
fun setStrokeWidth(width: Int) {
paint.strokeWidth = dpToPx(width).toFloat()
invalidate() // 重绘View
}
// 将dp转换为px
private fun dpToPx(dp: Int): Int {
val density = resources.displayMetrics.density
return (dp * density).toInt()
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.Shader
import android.util.AttributeSet
import android.view.View
import com.base.scanqrclear.R
class CircleProgressBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val arcPaint: Paint
private val bgPaint: Paint
private val path: Path
private val bounds: RectF
private var progress = 0.0f // 进度
private var colorArray = intArrayOf()
init {
arcPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.STROKE
strokeWidth = dpToPx(6f)
strokeCap = Paint.Cap.ROUND
}
bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = Color.TRANSPARENT
style = Paint.Style.STROKE
strokeWidth = dpToPx(6f)
strokeCap = Paint.Cap.ROUND
}
path = Path().apply {
}
bounds = RectF()
colorArray = intArrayOf(
context.getColor(R.color.color_ffae00),
context.getColor(R.color.color_fff5c3),
context.getColor(R.color.color_ff6400),
)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 考虑Paint的strokeWidth,调整RectF的边界
val strokeWidth: Float = bgPaint.getStrokeWidth()
val halfStrokeWidth = strokeWidth / 2
// 绘制完整圆的背景
path.reset()
path.addCircle(
width / 2f,
height / 2f,
(Math.max(width, height) - strokeWidth) / 2,
Path.Direction.CW
)
canvas.drawPath(path, bgPaint)
// 绘制完整圆的进度
path.reset()
val sweepAngleForProgress: Float = 360 * progress
// 设置渐变色
val shader = LinearGradient(
width / 2f, 0f, // 起点坐标
width / 2f, height.toFloat(), // 终点坐标
colorArray, // 渐变颜色
null, // 颜色位置(null表示均匀分布)
Shader.TileMode.CLAMP // 填充模式
)
arcPaint.shader = shader
// 从圆的上方开始绘制
path.addArc(
RectF(
halfStrokeWidth,
halfStrokeWidth,
width - halfStrokeWidth,
height - halfStrokeWidth
), 270f, sweepAngleForProgress
)
canvas.drawPath(path, arcPaint)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val desiredWidth = dpToPx(144f)
val desiredHeight = dpToPx(144f)
setMeasuredDimension(resolveSize(desiredWidth, widthMeasureSpec), resolveSize(desiredHeight, heightMeasureSpec))
}
fun set(strokeWidth: Float, colorArray: IntArray) {
val width = dpToPx(strokeWidth)
arcPaint.strokeWidth = width
bgPaint.strokeWidth = width
this.colorArray = colorArray
}
fun setProgress(progress: Float) {
this.progress = progress
invalidate()
}
private fun dpToPx(dp: Float): Float {
return dp * resources.displayMetrics.density
}
private fun resolveSize(desiredSize: Float, measureSpec: Int): Int {
val mode = MeasureSpec.getMode(measureSpec)
val size = MeasureSpec.getSize(measureSpec)
return when (mode) {
MeasureSpec.EXACTLY -> size
MeasureSpec.AT_MOST -> Math.min(desiredSize.toInt(), size)
else -> desiredSize.toInt()
}
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.Shader
import android.util.AttributeSet
import android.view.View
import com.base.scanqrclear.R
class MyProgressBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private var progress: Int = 0
private var maxProgress: Int = 100
private var cornerRadius: Float = 0f
private var progressColor: Int = 0
private var backgroundColor: Int = 0
private var startColor: Int = 0
private var endColor: Int = 0
private var progressText: String = ""
private var textColor: Int = 0
private var progressDirection: Int = PROGRESS_DIRECTION_LEFT_TO_RIGHT
private var shader: Shader? = null
private val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
strokeWidth = 5f
}
private val rect by lazy { RectF(0f, 0f, width.toFloat(), height.toFloat()) }
private val rectProgress by lazy { RectF() }
private val textPaint by lazy {
Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
textSize = 28f
color = textColor
}
}
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyProgressBar)
progress = typedArray.getInt(R.styleable.MyProgressBar_progress, 0)
maxProgress = typedArray.getInt(R.styleable.MyProgressBar_max, 100)
cornerRadius = typedArray.getDimension(R.styleable.MyProgressBar_cRadius, 0f)
progressColor = typedArray.getColor(R.styleable.MyProgressBar_pColor, 0)
backgroundColor = typedArray.getColor(R.styleable.MyProgressBar_pBgColor, 0)
startColor = typedArray.getColor(R.styleable.MyProgressBar_pStartColor, 0)
endColor = typedArray.getColor(R.styleable.MyProgressBar_pEndColor, 0)
progressText = typedArray.getString(R.styleable.MyProgressBar_pText) ?: ""
textColor = typedArray.getColor(R.styleable.MyProgressBar_pTextColor, 0)
progressDirection = typedArray.getInt(
R.styleable.MyProgressBar_progressDirection,
PROGRESS_DIRECTION_LEFT_TO_RIGHT
)
typedArray.recycle()
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = backgroundColor
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint)
val progressWidth = (width * progress / maxProgress).toFloat()
when (progressDirection) {
PROGRESS_DIRECTION_LEFT_TO_RIGHT -> {
rectProgress.set(0f, 0f, progressWidth, height.toFloat())
}
PROGRESS_DIRECTION_RIGHT_TO_LEFT -> {
rectProgress.set(width - progressWidth, 0f, width.toFloat(), height.toFloat())
}
}
paint.color = progressColor
if (startColor != 0 && endColor != 0) {
shader = LinearGradient(
0f,
0f,
progressWidth,
0f,
startColor,
endColor,
Shader.TileMode.CLAMP
)
paint.shader = shader
canvas.drawRoundRect(rectProgress, cornerRadius, cornerRadius, paint)
paint.shader = null
} else {
canvas.drawRoundRect(rectProgress, cornerRadius, cornerRadius, paint)
}
if (progressText.isNotEmpty()) {
val textWidth = textPaint.measureText(progressText)
val textX = width - paddingRight - textWidth - 34
canvas.drawText(progressText, textX, (height / 2).toFloat() + 10, textPaint)
}
}
fun setProgress(progress: Int) {
this.progress = progress.coerceAtMost(maxProgress)
invalidate()
}
fun getProgress(): Int = progress
fun setColor(backgroundColor: Int, progressColor: Int) {
this.backgroundColor = backgroundColor
this.progressColor = progressColor
invalidate()
}
companion object {
const val PROGRESS_DIRECTION_LEFT_TO_RIGHT = 0
const val PROGRESS_DIRECTION_RIGHT_TO_LEFT = 1
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.Typeface
import android.util.AttributeSet
import android.view.View
import android.view.animation.OvershootInterpolator
import com.base.scanqrclear.R
class RoundProgressBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private var ringPaint: Paint = Paint()
private var ringProgressPaint: Paint = Paint()
private var textPaint: Paint = Paint()
private var ringColor: Int
private var ringProgressColor: Int
private var textColor: Int
private var textSize: Float
private var ringWidth: Float
private var max: Int = 100
private var progress: Int = 0
private var showTextProgress: Boolean = true
private var styles: Int = 0
private val STROKE = 0
private val FULL = 1
init {
context.theme.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar, defStyleAttr, 0)
.apply {
try {
ringColor = getColor(R.styleable.RoundProgressBar_ringColor, Color.GRAY)
ringProgressColor =
getColor(R.styleable.RoundProgressBar_ringProgressColor, Color.GREEN)
textColor = getColor(R.styleable.RoundProgressBar_textColor, Color.GREEN)
textSize = getDimension(R.styleable.RoundProgressBar_textSize, 16f)
ringWidth = getDimension(R.styleable.RoundProgressBar_ringWidth, 5f)
max = getInteger(R.styleable.RoundProgressBar_maxpro, 100)
progress = getInteger(R.styleable.RoundProgressBar_progresspro, 0)
showTextProgress =
getBoolean(R.styleable.RoundProgressBar_showTextProgress, true)
styles = getInt(R.styleable.RoundProgressBar_style, 0)
} finally {
recycle()
}
}
initPaint()
}
private fun initPaint() {
ringPaint = Paint().apply {
color = ringColor
style = Paint.Style.STROKE
strokeWidth = ringWidth
isAntiAlias = true
}
ringProgressPaint = Paint().apply {
color = ringProgressColor
strokeWidth = ringWidth
strokeCap = Paint.Cap.ROUND
isAntiAlias = true
when (styles) {
STROKE -> style = Paint.Style.STROKE
FULL -> style = Paint.Style.FILL_AND_STROKE
}
}
textPaint = Paint().apply {
color = textColor
textSize = this@RoundProgressBar.textSize
typeface = Typeface.DEFAULT_BOLD
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val xCenter = width / 2f
val yCenter = height / 2f
val radius = (xCenter - ringWidth / 2).toInt()
canvas.drawCircle(xCenter, yCenter, radius.toFloat(), ringPaint)
val rectF = RectF(xCenter - radius, yCenter - radius, xCenter + radius, yCenter + radius)
when (styles) {
STROKE -> canvas.drawArc(
rectF, 270f,
-(progress * 360 / max).toFloat(), false, ringProgressPaint
)
FULL -> if (progress != 0) canvas.drawArc(
rectF, 270f,
-(progress * 360 / 100).toFloat(), true, ringProgressPaint
)
}
val text = "$progress%"
val textWidth = textPaint.measureText(text)
if (showTextProgress && progress != 0 && styles == STROKE) {
canvas.drawText(text, xCenter - textWidth / 2, yCenter + textSize / 2, textPaint)
}
}
fun getMax(): Int = max
fun setMax(max: Int) {
if (max < 0) throw IllegalArgumentException("max not less than 0")
this.max = max
}
fun getProgress(): Int = progress
fun setProgress(progress: Int) {
if (progress < 0) throw IllegalArgumentException("progress not less than 0")
if (progress > max) this.progress = max
if (progress <= max) {
this.progress = progress
postInvalidate()
}
}
fun setProgress(progress: Int, useAnimation: Boolean) {
if (progress < 0) throw IllegalArgumentException("progress not less than 0")
if (progress > max) this.progress = max
if (useAnimation) {
ValueAnimator.ofInt(0, progress).apply {
addUpdateListener { animation ->
this@RoundProgressBar.progress = animation.animatedValue as Int
postInvalidate()
}
interpolator = OvershootInterpolator()
duration = 1000
start()
}
} else {
this.progress = progress
postInvalidate()
}
}
fun getRingColor(): Int = ringColor
fun setRingColor(ringColor: Int) {
this.ringColor = ringColor
}
fun getRingProgressColor(): Int = ringProgressColor
fun setRingProgressColor(ringProgressColor: Int) {
this.ringProgressColor = ringProgressColor
}
fun getTextColor(): Int = textColor
fun setTextColor(textColor: Int) {
this.textColor = textColor
}
fun getTextSize(): Float = textSize
fun setTextSize(textSize: Float) {
this.textSize = textSize
}
fun getRingWidth(): Float = ringWidth
fun setRingWidth(ringWidth: Float) {
this.ringWidth = ringWidth
}
}
\ No newline at end of file
package com.base.scanqrclear.luma
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.base.scanqrclear.R
class TripleSeekBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
}
private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.STROKE
}
private val selectedLinePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.STROKE
}
private var radius: Float = 0f
private var strokeWidth: Float = 0f
private var defaultColor = 0
private var selectedColor = 0
private var segments = listOf(true, true, false) // 默认第一个圆点选中
private var _selection = MutableLiveData(1)
val selection: LiveData<Int> = _selection
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.TripleSeekBar)
defaultColor = typedArray.getColor(R.styleable.TripleSeekBar_default_color, 0)
selectedColor = typedArray.getColor(R.styleable.TripleSeekBar_selected_color, 0)
radius = typedArray.getDimension(R.styleable.TripleSeekBar_width, 0f)
strokeWidth = typedArray.getDimension(R.styleable.TripleSeekBar_pHeight, 0f)
linePaint.strokeWidth = strokeWidth
linePaint.color = defaultColor
selectedLinePaint.strokeWidth = strokeWidth
selectedLinePaint.color = selectedColor
typedArray.recycle()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val usableWidth = width - paddingLeft - paddingRight
val segmentWidth = usableWidth / 3
segments.forEachIndexed { index, selected ->
val x = segmentWidth * index + segmentWidth / 2 + paddingLeft
val y = height / 2f
// 绘制线段
if (index < 2) {
val nextX = segmentWidth * (index + 1) + segmentWidth / 2 + paddingLeft
val paint = if (segments[index + 1]) selectedLinePaint else linePaint
canvas.drawLine(x.toFloat(), y, nextX.toFloat(), y, paint)
}
paint.color = if (selected) selectedColor else defaultColor
canvas.drawCircle(x.toFloat(), y, radius, paint)
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
val usableWidth = width - paddingLeft - paddingRight
val segmentWidth = usableWidth / 3
val x = event.x
val y = event.y
val index = ((x - paddingLeft) / segmentWidth).toInt().coerceIn(0, 2)
when (event.action) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
if (event.action == MotionEvent.ACTION_DOWN) {
_selection.value = index
}
segments = List(segments.size) { i -> i <= index }
invalidate()
}
MotionEvent.ACTION_UP -> {
_selection.value = index
}
}
return true
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment