实现效果
实现逻辑
利用TypeValue.applyDimension方法将1mm转化成像素,以此为步长循环绘制刻度,中间需要处理一下整值和半值的线条长度以及对应的数字标识。
TypeValue.applyDimension方法说明
/**
* Converts an unpacked complex data value holding a dimension to its final floating
* point value. The two parameters <var>unit</var> and <var>value</var>
* are as in {@link #TYPE_DIMENSION}.
*
* @param unit The unit to convert from.
* @param value The value to apply the unit to.
* @param metrics Current display metrics to use in the conversion --
* supplies display density and scaling information.
*
* @return The complex floating point value multiplied by the appropriate
* metrics depending on its unit.
*/
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
复制代码
毫米转像素
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, resources.displayMetrics)
实现代码
class RulerView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : View(context, attrs, defStyle) {
/** 步长,为每毫米对应的像素值 **/
private var mStep: Float = 0f
/** 当前刻度所在的位置 **/
private var mIndex: Float = 0f
/** 当前刻度的索引值 **/
private var mLineCount: Int = 0
/** 普通刻度的高度 **/
private var mNormalLineHeight = 10f.toDp()
/** 半值刻度的高度,如5mm,15mm **/
private var mHalfLineHeight = 15f.toDp()
/** 整值刻度的高度,如0mm,10mm,20mm **/
private var mIntegerLineHeight = 20f.toDp()
/** 刻度值线宽 **/
private var mCurrentLineHeight: Float = mNormalLineHeight
private var mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
init {
mStep = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, resources.displayMetrics)
mPaint.color = Color.BLACK
mPaint.strokeWidth = 2f
mPaint.textSize = 14f.toDp()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
// 初始化第一个刻度所在的位置,为一个文字的高度,这里主要是为了让0mm的刻度值显示出来
mIndex = mPaint.getFontMetrics(null)
mLineCount = 0
// 同理,最大值的后面也加了一个文字的间隔
while (mIndex <= measuredHeight - mPaint.getFontMetrics(null)) {
mCurrentLineHeight = when {
// 整值
(mLineCount % 10) == 0 || mLineCount == 0 -> mIntegerLineHeight
// 半值
(mLineCount) % 5 == 0 -> mHalfLineHeight
// 普通值
else -> mNormalLineHeight
}
canvas?.drawLine(mCurrentLineHeight, mIndex, 0f, mIndex, mPaint)
// 绘制刻度值文字
if ((mLineCount % 10) == 0 || mLineCount == 0) {
canvas?.drawText("${mLineCount / 10}cm", mCurrentLineHeight + 5, mIndex + mPaint.getFontMetrics(null) / 3, mPaint)
}
mIndex += mStep
mLineCount++
}
}
private fun Float.toDp(): Float {
return (this * Resources.getSystem().displayMetrics.density + 0.5f)
}
}
复制代码
需要注意的是,为了能让刻度0和最大的刻度值显示出来,这里手动加了个上下值为刻度值字体行高的间距。
至于类似于触摸指针获取当前厘米值的功能,有待后续开发,不过也不难,只是过多了个了值的计算过程而已。
代码不多,欢迎指正。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END