最近在项目中需要使用到的心电Ecg显示效果,本来打算使用sdk方的视图组件的,但是奈何他们的组件问题太多了。比如网格不对齐(强迫症表示这个无法忍),组件不支持静态显示数据等等问题。所以打算自己写一个用来做主页面的心电数据展示。
首先要实现以下几个功能点:
1.网格的大小,颜色可控。
2.心电线条的颜色粗细可控。
3.无论传入的数据源长度是多少,都要均匀的显示在表格上(按一定的比例尺缩放或者扩展)
之后可能会实现动态显示数据的部分,会在本篇博客更新。
技术实现要点:
传入的数据源是String字符串,类似于:"0.101253886148333549,0.001253886148333549,0.003036087844520807,0.002440808573737741"
这样的数据,所以这里要对传入的数据进行处理,根据数据的个数确定屏幕上一共要均匀连线多少个点。
代码实现:
class EcgShowView : View {
private var mWidth: Float = 0.toFloat()
private var mHeight: Float = 0.toFloat()
private var paint: Paint? = null
private var path: Path? = null
private var dataStrList: Array<String>? = null
private var intervalNumHeart: Int = 0
private var intervalRowHeart: Float = 0.toFloat()
private var intervalColumnHeart: Float = 0.toFloat()
private var data: FloatArray? = null
private var mHeartLinestrokeWidth: Float = 0.toFloat()
private var row: Int = 0
private var intervalRow: Float = 0.toFloat()
private var column: Int = 0
private var intervalColumn: Float = 0.toFloat()
private var mGridLinestrokeWidth: Float = 0.toFloat()
private var mGridstrokeWidthAndHeight: Float = 0.toFloat()
//心电
private val MAX_VALUE = 20f //峰值
private val HEART_LINE_STROKE_WIDTH = 5f
//网格
private val GRID_LINE_STROKE_WIDTH = 3f
private val GRID_WIDTH_AND_HEIGHT = 10f
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init()
}
private fun init() {
paint = Paint()
path = Path()
//setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
mWidth = measuredWidth.toFloat()
mHeight = measuredHeight.toFloat()
mGridLinestrokeWidth = dip2px(GRID_LINE_STROKE_WIDTH).toFloat()
mGridstrokeWidthAndHeight = dip2px(GRID_WIDTH_AND_HEIGHT).toFloat()
column = (mWidth / mGridstrokeWidthAndHeight).toInt();
intervalColumn = mWidth / column
row = (mHeight / mGridstrokeWidthAndHeight).toInt()
intervalRow = mHeight / row
mHeartLinestrokeWidth = dip2px(HEART_LINE_STROKE_WIDTH).toFloat()
initData()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//绘制网格
paint!!.style = Paint.Style.STROKE
paint!!.color = Color.parseColor("#D8D8D8")
paint!!.strokeWidth = mGridLinestrokeWidth
paint!!.isAntiAlias = true
for (i in 0..column) {
val iTempC = i * intervalColumn
path!!.moveTo(iTempC, 0f)
path!!.lineTo(iTempC, mHeight)
}
for (i in 0..row) {
path!!.moveTo(0f, i * intervalRow)
path!!.lineTo(mWidth, i * intervalRow)
}
canvas.drawPath(path!!, paint!!)
//绘制心电图
if (data == null || data!!.size == 0) {
return
}
paint!!.reset()
path!!.reset()
paint!!.style = Paint.Style.STROKE
paint!!.color = Color.parseColor("#31CE32")
paint!!.strokeWidth = mGridLinestrokeWidth
paint!!.isAntiAlias = true
path!!.moveTo(0f, mHeight / 2)
var nowX: Float
var nowY: Float
for (i in data!!.indices) {
nowX = i * intervalRowHeart
var dataValue = data!![i]
if (dataValue > 0) {
if (dataValue > MAX_VALUE * 0.8f) {
dataValue = MAX_VALUE * 0.8f
}
} else {
if (dataValue < -MAX_VALUE * 0.8f) {
dataValue = -(MAX_VALUE * 0.8f)
}
}
nowY = mHeight / 2 - dataValue * intervalColumnHeart
path!!.lineTo(nowX, nowY)
}
canvas.drawPath(path!!, paint!!)
}
fun setData(dataStr: String) {
dataStrList = dataStr.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
initData()
}
private fun initData() {
try {
var dataLength = dataStrList!!.size
if (dataLength > mWidth) {
dataLength = mWidth.toInt()
}
data = FloatArray(dataLength)
for (i in 0 until dataLength) {
data!![i] = java.lang.Float.parseFloat(dataStrList!![i])
}
intervalNumHeart = data!!.size
intervalRowHeart = mWidth / intervalNumHeart
intervalColumnHeart = mHeight / (MAX_VALUE * 2)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun px2dip(px: Int): Int {
val scale = context.resources.displayMetrics.density
return (px / scale + 0.5f).toInt()
}
private fun dip2px(dipValue: Float): Int {
val scale = context.resources.displayMetrics.density
return (dipValue * scale + 0.5f).toInt()
}
}
Github项目地址:
https://github.com/jiangzhengnan/UI
最近会把实现的UI效果都集中到一个库里面,求start~