1、前言
书接上一回 5分钟带你了解Android Progress Bar 2
上一回说到,要自定义ProgressBar,自定义一个ProgressBar,但功用不如原生的完好版!!首要还是用来了解怎么写一个进展条,然后引出后面的,功用肯定没有原生的那么齐全啦。
假如您有任何疑问、对文章写的不满意、发现错误或许有更好的办法,欢迎在谈论、私信或邮件中提出,十分感谢您的支撑。
看看作用先
2、条形ProgressBar简单仿写
(1)预备好Attribute
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ZProgressBar2">
<attr name="zTextColor" format="color" />
<attr name="zBarHeight" format="dimension"/>
<attr name="zMax" format="float" />
<attr name="zProgress" format="float" />
<attr name="zProgressColor" format="string" />
<attr name="zRemainColor" format="string" />
<attr name="zTextVisibility" format="boolean"/>
</declare-styleable>
</resources>
随意想点特点啦
(2)新建一个ZProgressBar2.kt
class ZProgressBar2 @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {}
姓名随意,新建文件 -> 继承自 View -> 由编译器补全代码。
选@JvmOverloads的这条!这样Java也能用了
(3)预备好一些变量声明
声明啥,你自己看着办就行。我这儿根本便是预备了,Attribute中特点
/**
* 默许进展条色彩
*/
private val DEFAULT_PROGRESS_COLOR: Int = Color.parseColor("#FFA5E05B")
private val DEFAULT_REMAIN_COLOR: Int = Color.parseColor("#FFFFFFFF")
private val DEFAULT_TEXT_COLOR: Int = Color.parseColor("#FFFFFFFF")
/**
* 默许进展
*/
private val DEFAULT_MAX: Float = 100f
private val DEFAULT_PROGRESS: Float = 0f
/**
* 进展条最大值
*/
var mMax: Float = DEFAULT_MAX
var mMin: Float = DEFAULT_PROGRESS
/**
* 进展条当时进展值
*/
var mProgress: Float = DEFAULT_PROGRESS
/**
* 进展条色彩
* 完结
*/
var mProgressColor = DEFAULT_PROGRESS_COLOR
/**
* 进展条色彩
* 剩下
*/
var mRemainColor = DEFAULT_REMAIN_COLOR
/**
* 进展条高度
*/
var mBarHeight = 30f.dp
/**
* 剩下进展区域
*/
private val mRemainRectF = RectF(0f, 0f, 0f, 0f)
/**
* 已完结进展区域
*/
private val mProgressRectF = RectF(0f, 0f, 0f, 0f)
/**
* ANTI_ALIAS_FLAG 抗锯齿
* isAntiAlias 防抖动
* Paint.Cap.ROUND 笔画凸出成半圆形
*/
private val mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
strokeCap = Paint.Cap.ROUND
isAntiAlias = true
}
/**
* 进展文字色彩
*/
private var mTextColor = Color.WHITE
private var mTextVisibility = false
private var progressFormat = DecimalFormat("#")
(4)预备好读取Attribute的办法
记得在init中调用哈
/**
* 读取自定义的布局特点
*/
private fun initArr(attrs: AttributeSet?) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ZProgressBar2)
typedArray.run {
mMax = getFloat(R.styleable.ZProgressBar2_zMax, mMax)
mProgress = getFloat(R.styleable.ZProgressBar2_zProgress, mProgress)
mProgressColor =
getColor(R.styleable.ZProgressBar2_zProgressColor, DEFAULT_PROGRESS_COLOR)
mRemainColor =
getColor(R.styleable.ZProgressBar2_zRemainColor, DEFAULT_REMAIN_COLOR)
mBarHeight = getDimension(R.styleable.ZProgressBar2_zBarHeight, 30f.dp)
mTextColor = getColor(
R.styleable.ZProgressBar2_zTextColor,
DEFAULT_REMAIN_COLOR
)
mTextVisibility =
getBoolean(R.styleable.ZProgressBar2_zTextVisibility, true)
}
typedArray.recycle()
}
init{
initArr(attrs)
}
(5)在onDraw中制作
首要代码就在这了,没多少,看注释!
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
calculateProgressRect()
canvas?.run {
//先画剩下的,要让进展压在上面
mPaint.color = mRemainColor
//进展和剩下进展,便是两个圆角方形叠在一同
drawRoundRect(mRemainRectF, mBarHeight / 2, mBarHeight / 2, mPaint)
//再画进展
mPaint.color = mProgressColor
drawRoundRect(mProgressRectF, mBarHeight / 2, mBarHeight / 2, mPaint)
//然后文字在最上层
mPaint.textSize = mBarHeight * 0.5f
//格式化Progress
var mCurrentDrawText: String = progressFormat.format(mProgress * 100 / mMax)
//画文字的根本操作,先测一下宽度
val mDrawTextWidth = mPaint.measureText(mCurrentDrawText)
//要判别下进展的宽度,够不够画文字出来
if (mTextVisibility && mProgress > 0 && mProgressRectF.right > mDrawTextWidth) {
mPaint.color = mTextColor
drawText(
mCurrentDrawText,
mProgressRectF.right - mDrawTextWidth - mBarHeight * 0.4f,
//descent/ascent 关于文字的高度能够去看看相关文章
(height / 2.0f - (mPaint.descent() + mPaint.ascent()) / 2.0f).toInt().toFloat(),
mPaint
)
}
}
}
/**
* 很惯例的核算一个View的四个坐标的办法
*/
private fun calculateProgressRect() {
val ttop = (height - mBarHeight) / 2.0f
val bbottom = (height + mBarHeight) / 2.0f
mProgressRectF.run {
left = paddingLeft.toFloat()
top = ttop
/**
* 核算已完结进展的长度
*/
right = (width - paddingLeft - paddingRight) / (mMax * 1.0f) * mProgress + paddingLeft
bottom = bbottom
}
mRemainRectF.run {
left = paddingLeft.toFloat()
top = ttop
right = (width - paddingRight).toFloat()
bottom = bbottom
}
}
(6)露出更新办法
重写下set办法就好了,都去调用invalidate()办法。
/**
* 进展条最大值
*/
var mMax: Float = DEFAULT_MAX
set(value) {
field = value
invalidate()
}
var mMin: Float = DEFAULT_PROGRESS
set(value) {
field = value
invalidate()
}
/**
* 进展条当时进展值
*/
@set:Synchronized
var mProgress: Float = DEFAULT_PROGRESS
set(value) {
if (value == field) {
// No change from current.
return
}
//不能超过最大值,最小值啊
field = value.coerceIn(mMin, mMax)
invalidate()
}
/**
* 进展条色彩
* 完结
*/
var mProgressColor = DEFAULT_PROGRESS_COLOR
set(value) {
field = value
invalidate()
}
/**
* 进展条色彩
* 剩下
*/
var mRemainColor = DEFAULT_REMAIN_COLOR
set(value) {
field = value
invalidate()
}
/**
* 进展条高度
*/
var mBarHeight = 30f.dp
set(value) {
field = value
invalidate()
}
没啦,就这么多,一个看起来差不多的就行了,简单版~
(7)完好代码
下面是全部代码,以及调用代码
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import com.nf.framework.utillib.ext.dp
import com.nf.module_test.R
import java.text.DecimalFormat
/**
* 仿制ProgressBar
*/
class ZProgressBar2 @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
/**
* 默许进展条色彩
*/
private val DEFAULT_PROGRESS_COLOR: Int = Color.parseColor("#FFA5E05B")
private val DEFAULT_REMAIN_COLOR: Int = Color.parseColor("#FFFFFFFF")
private val DEFAULT_TEXT_COLOR: Int = Color.parseColor("#FFFFFFFF")
/**
* 默许进展
*/
private val DEFAULT_MAX: Float = 100f
private val DEFAULT_PROGRESS: Float = 0f
/**
* 进展条最大值
*/
var mMax: Float = DEFAULT_MAX
set(value) {
field = value
invalidate()
}
var mMin: Float = DEFAULT_PROGRESS
set(value) {
field = value
invalidate()
}
/**
* 进展条当时进展值
*/
@set:Synchronized
var mProgress: Float = DEFAULT_PROGRESS
set(value) {
if (value == field) {
// No change from current.
return
}
field = value.coerceIn(mMin, mMax)
invalidate()
}
/**
* 进展条色彩
* 完结
*/
var mProgressColor = DEFAULT_PROGRESS_COLOR
set(value) {
field = value
invalidate()
}
/**
* 进展条色彩
* 剩下
*/
var mRemainColor = DEFAULT_REMAIN_COLOR
set(value) {
field = value
invalidate()
}
/**
* 进展条高度
*/
var mBarHeight = 30f.dp
set(value) {
field = value
invalidate()
}
/**
* 剩下进展区域
*/
private val mRemainRectF = RectF(0f, 0f, 0f, 0f)
/**
* 已完结进展区域
*/
private val mProgressRectF = RectF(0f, 0f, 0f, 0f)
/**
* ANTI_ALIAS_FLAG 抗锯齿
*/
private val mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
/**
* 笔画凸出成半圆形
*/
strokeCap = Paint.Cap.ROUND
/**
* 防抖动
*/
isAntiAlias = true
}
/**
* 进展文字色彩
*/
private var mTextColor = Color.WHITE
private var mTextVisibility = false
private var progressFormat = DecimalFormat("#")
init {
initArr(attrs)
}
/**
* 读取自定义的布局特点
*/
private fun initArr(attrs: AttributeSet?) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ZProgressBar2)
typedArray.run {
mMax = getFloat(R.styleable.ZProgressBar2_zMax, mMax)
mProgress = getFloat(R.styleable.ZProgressBar2_zProgress, mProgress)
mProgressColor =
getColor(R.styleable.ZProgressBar2_zProgressColor, DEFAULT_PROGRESS_COLOR)
mRemainColor =
getColor(R.styleable.ZProgressBar2_zRemainColor, DEFAULT_REMAIN_COLOR)
mBarHeight = getDimension(R.styleable.ZProgressBar2_zBarHeight, 30f.dp)
mTextColor = getColor(
R.styleable.ZProgressBar2_zTextColor,
DEFAULT_REMAIN_COLOR
)
mTextVisibility =
getBoolean(R.styleable.ZProgressBar2_zTextVisibility, true)
}
typedArray.recycle()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
calculateProgressRect()
canvas?.run {
mPaint.color = mRemainColor
drawRoundRect(mRemainRectF, mBarHeight / 2, mBarHeight / 2, mPaint)
mPaint.color = mProgressColor
drawRoundRect(mProgressRectF, mBarHeight / 2, mBarHeight / 2, mPaint)
mPaint.textSize = mBarHeight * 0.5f
var mCurrentDrawText: String = progressFormat.format(mProgress * 100 / mMax)
mPaint.color = mTextColor
val mDrawTextWidth = mPaint.measureText(mCurrentDrawText)
if (mTextVisibility && mProgress > 0 && mProgressRectF.right > mDrawTextWidth) {
drawText(
mCurrentDrawText,
mProgressRectF.right - mDrawTextWidth - mBarHeight * 0.4f,
(height / 2.0f - (mPaint.descent() + mPaint.ascent()) / 2.0f).toInt().toFloat(),
mPaint
)
}
}
}
private fun calculateProgressRect() {
val ttop = (height - mBarHeight) / 2.0f
val bbottom = (height + mBarHeight) / 2.0f
mProgressRectF.run {
left = paddingLeft.toFloat()
top = ttop
/**
* 核算已完结进展的长度
*/
right = (width - paddingLeft - paddingRight) / (mMax * 1.0f) * mProgress + paddingLeft
bottom = bbottom
}
mRemainRectF.run {
left = paddingLeft.toFloat()
top = ttop
right = (width - paddingRight).toFloat()
bottom = bbottom
}
}
}
<com.nf.module_test.seekbar.custom.ZProgressBar2
android:id="@+id/zpb_01"
android:layout_width="match_parent"
android:layout_height="40dp"
app:zBarHeight="40dp"
app:zTextColor="#ffffff"
app:zMax="100"
app:zProgress="50" />
作用如下
3、圆形ProgressBar
嘻嘻嘻,直的写出来了,圆的也的有一个吧,交互也得有吧?就在这个基础上,咱们再扩展下
(1)依然咱们需求预备好Attribute
这儿咱们直接在本来的基础上加一点吧
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ZProgressBar2">
<attr name="zTextColor" format="color" />
<attr name="zBarHeight" format="dimension" />
<attr name="zMax" format="float" />
<attr name="zProgress" format="float" />
<attr name="zProgressColor" format="string" />
<attr name="zRemainColor" format="string" />
<attr name="zTextVisibility" format="boolean" />
<attr name="zShape" format="integer">
<enum name="line" value="0"/>
<enum name="oval" value="1"/>
</attr>
<attr name="zFullDegree" format="integer" />
<attr name="zAnimationDuration" format="integer" />
<attr name="zDragEnabled" format="boolean" />
</declare-styleable>
</resources>
(2)持续在ZProgressBar2中添加一些变量声明
还有一些变量在后面看吧
/**
* 样式
*/
private var mShape = DEFAULT_SHAPE
/**
* 进展条的视点
*/
private var mMaxDegree: Int = DEFAULT_FULL_DEGREE
set(value) {
field = value.coerceIn(0,360)
}
/**
* Thumb对象
*/
private var mThumbDraw: Drawable? = null
/**
* Thumb对象约束宽高
*/
private var mThumbRadius = DEFAULT_BAR_WIDTH * 1.2f
/**
* TODO
*/
private var mAnimationDuration: Int = 0
/**
* 是否能够拖动
*/
private var mDragEnabled: Boolean = true
/**
* 圆弧的半径
*/
private var mCircleRadius: Float = 0f
/**
* 圆弧圆心方位
*/
private var centerX: Int = 0
/**
* 圆弧圆心方位
*/
private var centerY: Int = 0
private var mWidth: Int = 0
private var mHeight: Int = 0
(3)预备好读取Attribute的办法
这儿咱们接着之前的写好就行了
private fun initArr(attrs: AttributeSet?) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ZProgressBar2)
typedArray.run {
mMax = getFloat(R.styleable.ZProgressBar2_zMax, mMax)
mProgress = getFloat(R.styleable.ZProgressBar2_zProgress, mProgress)
mProgressColor = getColor(R.styleable.ZProgressBar2_zProgressColor, DEFAULT_PROGRESS_COLOR)
mRemainColor = getColor(R.styleable.ZProgressBar2_zRemainColor, DEFAULT_REMAIN_COLOR)
mBarHeight = getDimension(R.styleable.ZProgressBar2_zBarHeight, DEFAULT_BAR_WIDTH)
mTextColor = getColor(R.styleable.ZProgressBar2_zTextColor,DEFAULT_REMAIN_COLOR)
mTextVisibility = getBoolean(R.styleable.ZProgressBar2_zTextVisibility, tr
mMaxDegree = getInteger(R.styleable.ZProgressBar2_zFullDegree, DEFAULT_FULL_DEGREE)
mAnimationDuration = getInteger(R.styleable.ZProgressBar2_zAnimationDuration, 500)
mDragEnabled = getBoolean(R.styleable.ZProgressBar2_zDragEnabled, DEFAULT_ENABLE_TOUCH)
mShape = getInteger(R.styleable.ZProgressBar2_zShape, DEFAULT_SHAPE)
mThumbDraw = getDrawable(R.styleable.ZProgressBar2_zThumbDrawable)
mThumbRadius = getDimension(R.styleable.ZProgressBar2_zThumbRadius, DEFAULT_BAR_WIDTH * 1.2f)
}
typedArray.recycle()
}
(4)处理onMeasure
/**
* left:矩形左面线条离 y 轴的间隔
* top:矩形上面线条离 x 轴的间隔
* right:矩形右边线条离 y 轴的间隔
* bottom:矩形底部线条离 x 轴的间隔
* 这儿我没有专门去处理layout_height、width,只处理固定宽高,交给你自己做啦
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
if (mWidth == 0 || mHeight == 0) {
mWidth = measuredWidth
mHeight = measuredHeight
//两者取最大
mCircleRadius = mWidth.coerceAtMost(mHeight) / 2f
//给BarHeight一个默许值,假如没有
if (mBarHeight <= 0) mBarHeight = mCircleRadius / 12f
//实践的制作需求考虑到Thumb可能会超出中心圆一点点,所以减掉,假如没有就去减掉进展条的
mCircleRadius -= if (mThumbDraw == null) {
mBarHeight * 0.6f
} else {
mThumbRadius * 0.6f
}
centerX = mWidth / 2
centerY = mHeight / 2
//进展的弧形便是靠这个
mProgressRectF.run {
left = centerX - mCircleRadius
top = centerY - mCircleRadius
right = centerX + mCircleRadius
bottom = centerY + mCircleRadius
}
}
}
(5)处理下直线和圆的onDraw
这儿经过读取的mShape,来判别是显示哪个。onDrawDir便是前面写的直线bar啦
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (mShape == 0) {
onDrawDir(canvas)
} else {
onDrawArc(canvas)
}
}
思考下,由于咱们是支撑指定最大弧度的,所以进展条其实便是一个扇形,然后只画边就行了(不然你也能够用两个圆堆叠达到相同的作用)
一个扇形画当时进展,一个画剩下进展,完事。再到中间画一个文字,进展条前端画一个thumb~~~
private fun onDrawArc(canvas: Canvas?) {
canvas?.run {
/**
* 进展条起始点
* shr 1 便是/2的意思
*/
val startAngle: Float = (90 + ((360 - mMaxDegree) shr 1)).toFloat()
//当时进展的百分比
val sweep1: Float = mMaxDegree * (mProgress / mMax)
//剩下进展的百分比
val sweep2: Float = mMaxDegree - sweep1
//由于咱们是画进展条的,只需求画周边就行了,所用空心 描边
mBarPaint.style = Paint.Style.STROKE
//画笔的strokeWidth就相当于进展条宽度了
mBarPaint.strokeWidth = mBarHeight
mBarPaint.color = mRemainColor
//很简单,制作区域咱们现已预备好了mProgressRectF
//剩下起点用’当时进展起点+初始起点‘便是剩下进展的起点,结束明显便是sweep2
drawArc(mProgressRectF, startAngle + sweep1, sweep2, false, mBarPaint)
mBarPaint.color = mProgressColor
//当时进展起点当然便是初始起点,结束当然是sweep1
drawArc(mProgressRectF, startAngle, sweep1, false, mBarPaint)
/**
* 依据三角函数来核算出thumb的XY值
* PS:你可能需求必定的数学知识和Android的坐标系知识
* 假如你不会,记住就行,由于都相同~或许留言
*/
val progressRadians =
(((360.0f - mMaxDegree) /2 + sweep1) / 180 * Math.PI).toFloat()
val thumbX: Float =
centerX - mCircleRadius * sin(progressRadians.toDouble()).toFloat()
val thumbY: Float =
centerY + mCircleRadius * cos(progressRadians.toDouble()).toFloat()
/**
* 依据thumb的半径画出drawable对象
*/
mThumbDraw?.let {
it.setBounds(
(thumbX - mThumbRadius / 2).toInt(), (thumbY - mThumbRadius / 2).toInt(),
(thumbX + mThumbRadius / 2).toInt(), (thumbY + mThumbRadius / 2).toInt())
it.draw(canvas)
}
/**
* 文字制作
*/
if (mTextVisibility) {
mTextPaint.textSize = (mCircleRadius.toInt() shr 1).toFloat()
mTextPaint.color = Color.parseColor("#FFCB47")
val textProgress: String = progressFormat.format(100f * mProgress / mMax)
val textLen: Float = mTextPaint.measureText(textProgress)
mTextPaint.getTextBounds("8", 0, 1, mTextBounds)
val textProgressHeight: Int = mTextBounds.height()
val extra: Float =
if (textProgress.startsWith("1")) -mTextPaint.measureText("1") / 2 else 0F
/**
* 首要是核算文字的左上角坐标
* 让它画在中间
*/
drawText(
textProgress,
centerX - textLen / 2 + extra,
centerY + textProgressHeight / 2f,
mTextPaint
)
/**
* shr 2 便是/4啦
*/
mTextPaint.textSize = (mCircleRadius.toInt() shr 2).toFloat()
drawText(
"%",
centerX + textLen / 2 + extra + 5,
centerY + textProgressHeight / 2f,
mTextPaint
)
}
}
}
到这儿,制作就根本完毕了。接下啦咱们要考虑点击事情的问题了
(6)点击事情的处理
咱们直接分为两种,一种点击,一种按住滑动。话不多说,全在注释里
private var isDragging = true
private var lastProgress = -1F
/**
* mDragEnabled变量用于控制是否启用拖拽功用
* checkOnArc办法判别点击是否在圆弧上;
* thumbProgress办法依据点击的方位核算进展并将进展更新到控件上;
* isDragging变量用于标识当时是否在拖拽。
* 当用户点击时,假如检测到点击方位在圆弧上,则执行进展核算并设置isDragging变量为true。
* 当用户拖动时,假如当时正在拖拽,则执行进展核算;
* 当用户抬起手指时,将isDragging设置为false。
* 在办法结束,返回true,表明该办法现已处理了该事情,不需求再向上传递。
*/
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
if (!mDragEnabled) {
return super.onTouchEvent(event)
}
val currentX = event.x
val currentY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN ->
if (checkOnArc(currentX, currentY)) {
thumbProgress(currentX, currentY)
isDragging = true
}
MotionEvent.ACTION_MOVE -> if (isDragging) {
thumbProgress(currentX, currentY)
}
MotionEvent.ACTION_UP -> isDragging = false
}
return true
}
/**
* 保证滑块的拖动不会在进展条的相反方向进行。
* 首要,经过核算当时点相对于中心点的极角
* 并将其转换为当时进展。
* 接着,将该进展与当时最终一次进展(lastProgress)进行比较
* 假如两者差值小于最大值的一半,则更新当时进展(mProgress)为该进展;
* 不然,当时进展不变。
*/
private fun thumbProgress(currentX: Float, currentY: Float) {
var nextProgress = calculateDegree(currentX, currentY) / mMaxDegree * mMax
nextProgress = nextProgress.coerceAtMost(mMax).coerceAtLeast(mMin)
val delta = abs(nextProgress - lastProgress)
if (delta < mMax / 2 || lastProgress == -1F) {
lastProgress = nextProgress
mProgress = nextProgress
}
}
/**
* 检查间隔是否在圆弧的内圈和外圈之间,并检查视点是否在圆弧的开端和完毕方位的必定范围内
* 首要调用calculateDistance函数核算给定点(currentX,currentY)与(centerX,centerY)之间的间隔。
* 然后调用calculateDegree函数核算给定点与圆心之间的视点。
* 最终,该函数经过比较这个间隔和视点与圆弧上的特定范围,来判别给定的点是否在圆弧范围内。
* return 给定的点(currentX,currentY)是否在一个弧形范围内
*/
private fun checkOnArc(currentX: Float, currentY: Float): Boolean {
val distance = calculateDistance(currentX, currentY, centerX.toFloat(), centerY.toFloat())
val degree = calculateDegree(currentX, currentY)
return distance > mCircleRadius - mBarHeight * 3 //点击区域弧内
&& distance < mCircleRadius + mBarHeight * 3 //点击区域弧外
&& degree >= -8 && //圆弧开端方位
degree <= mMaxDegree + 8 //圆弧完毕方位
}
/**
* 核算两点(x1,y1)和(x2,y2)之间的间隔
* 经过公式√((x1-x2)+(y1-y2))核算两点间的欧几里得间隔
*/
private fun calculateDistance(x1: Float, y1: Float, x2: Float, y2: Float): Float {
return sqrt(((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)).toDouble()).toFloat()
}
/**
* 核算当时点(currentX,currentY)与圆心(centerX,centerY)之间的视点
* 首要,经过反正切函数atan核算出视点a1
* 接着,依据当时点的方位与圆心的联系,分三种状况谈论
* 假如当时点在圆心下方,则在a1上加180
* 假如当时点在圆心上方且在圆心右方,则在a1上加360
* 最终,减去360与mMaxDegree的差的一半,并返回结果
* 这样就得到了当时点相对于圆心的视点值,并约束在了mMaxDegree范围内。
*/
private fun calculateDegree(currentX: Float, currentY: Float): Float {
var a1 =
(atan((1.0f * (centerX - currentX) / (currentY - centerY)).toDouble()) / Math.PI * 180).toFloat()
if (currentY < centerY) {
a1 += 180f
} else if (currentY > centerY && currentX > centerX) {
a1 += 360f
}
return a1 - (360 - mMaxDegree) / 2
}
(7)完结!
调用下~
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:layout_height="wrap_content">
<com.nf.module_test.seekbar.custom.ZProgressBar2
android:id="@+id/zpb_01"
android:layout_width="100dp"
android:layout_height="100dp"
app:zBarHeight="5dp"
app:zTextColor="#ffffff"
app:zShape="oval"
app:zFullDegree="90"
app:zThumbDrawable="@drawable/icon_seekbar_thum"
app:zMax="100"
app:zProgress="50" />
<com.nf.module_test.seekbar.custom.ZProgressBar2
android:id="@+id/zpb_02"
android:layout_width="100dp"
android:layout_height="100dp"
app:zBarHeight="5dp"
app:zFullDegree="180"
app:zMax="100"
app:zProgress="50"
app:zShape="oval"
app:zTextColor="#ffffff"
app:zThumbDrawable="@drawable/icon_seekbar_thum" />
<com.nf.module_test.seekbar.custom.ZProgressBar2
android:id="@+id/zpb_03"
android:layout_width="100dp"
android:layout_height="100dp"
app:zBarHeight="5dp"
app:zTextColor="#ffffff"
app:zShape="oval"
app:zFullDegree="360"
app:zThumbDrawable="@drawable/icon_seekbar_thum"
app:zMax="100"
app:zProgress="50" />
</LinearLayout>
看看作用
完好代码ZProgressBar2.kt 和 完好代码attr.xml
还有许多功用,都没有做完,不过这些看完,相信你现已能够自己接着来了,个人认为,自定义View的中心都在怎么准确的核算View的坐标,那么这个圆形的相关,根本都在三角函数上啦。
结束
这个系列现已3篇了,还有许多奇怪的进展条我都没有写,由于写了3篇了我感觉我的脑子里都是进展条,所以先暂停一会啦,当然假如谁真的很需求下一篇,谈论、私信、邮箱我,我会速更第四篇,嘻嘻x.x
那么下篇见
“开启成长之旅!这是我参与「日新方案 2 月更文挑战」的第 3 天,点击查看活动概况”