diff --git a/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..ff29bdf --- /dev/null +++ b/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt @@ -0,0 +1,201 @@ +package com.casic.detector.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.PointF +import android.graphics.SweepGradient +import android.util.AttributeSet +import android.view.View +import com.casic.detector.R +import com.pengxh.kt.lite.extensions.dp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //需要渲染的数据点集合 + private val points = ArrayList() + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor(R.styleable.RadarScanView_radar_borderColor, Color.GRAY) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 150) + type.recycle() + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = borderColor + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + /** + * 上下翻转画布,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画数据点 + points.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * */ + fun renderPointData(dataPoints: ArrayList) { + dataPoints.forEach { + val result = recursionAngle(it.angle) + //转为弧度 + val dataAngle = (result * Math.PI / 180).toFloat() + val dataDistance = recursionDistance(it.distance.dp2px(context).toFloat()) + + //计算实际圆心坐标 + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + + points.add(PointF(x, y)) + } + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(val angle: Float, val distance: Float) + + /** + * 递归计算周期性角度 + * */ + private fun recursionAngle(angle: Float): Float { + return if (angle < -360) { + recursionAngle(angle + 360) + } else if (angle > 360) { + recursionAngle(angle - 360) + } else { + angle + } + } + + /** + * 递归计算周期性距离 + * */ + private fun recursionDistance(distance: Float): Float { + return if (distance <= 0) { + 0f + } else if (distance >= radius) { + radius.toFloat() + } else { + distance + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..ff29bdf --- /dev/null +++ b/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt @@ -0,0 +1,201 @@ +package com.casic.detector.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.PointF +import android.graphics.SweepGradient +import android.util.AttributeSet +import android.view.View +import com.casic.detector.R +import com.pengxh.kt.lite.extensions.dp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //需要渲染的数据点集合 + private val points = ArrayList() + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor(R.styleable.RadarScanView_radar_borderColor, Color.GRAY) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 150) + type.recycle() + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = borderColor + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + /** + * 上下翻转画布,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画数据点 + points.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * */ + fun renderPointData(dataPoints: ArrayList) { + dataPoints.forEach { + val result = recursionAngle(it.angle) + //转为弧度 + val dataAngle = (result * Math.PI / 180).toFloat() + val dataDistance = recursionDistance(it.distance.dp2px(context).toFloat()) + + //计算实际圆心坐标 + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + + points.add(PointF(x, y)) + } + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(val angle: Float, val distance: Float) + + /** + * 递归计算周期性角度 + * */ + private fun recursionAngle(angle: Float): Float { + return if (angle < -360) { + recursionAngle(angle + 360) + } else if (angle > 360) { + recursionAngle(angle - 360) + } else { + angle + } + } + + /** + * 递归计算周期性距离 + * */ + private fun recursionDistance(distance: Float): Float { + return if (distance <= 0) { + 0f + } else if (distance >= radius) { + radius.toFloat() + } else { + distance + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_search_marker_new.xml b/app/src/main/res/layout/dialog_search_marker_new.xml index 3404a43..0ea108e 100644 --- a/app/src/main/res/layout/dialog_search_marker_new.xml +++ b/app/src/main/res/layout/dialog_search_marker_new.xml @@ -1,16 +1,18 @@ - + android:background="@mipmap/bg_search_label" + android:gravity="center_horizontal" + android:orientation="vertical"> - + @@ -104,8 +105,6 @@ android:id="@+id/buttonLayout" android:layout_width="320dp" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/dp_10" android:layout_marginBottom="@dimen/dp_30" android:gravity="center_horizontal"> @@ -137,8 +136,4 @@ android:textColor="#CCCCCC" android:textSize="@dimen/sp_22" /> - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt b/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt new file mode 100644 index 0000000..ff29bdf --- /dev/null +++ b/app/src/main/java/com/casic/detector/widgets/RadarScanView.kt @@ -0,0 +1,201 @@ +package com.casic.detector.widgets + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.PointF +import android.graphics.SweepGradient +import android.util.AttributeSet +import android.view.View +import com.casic.detector.R +import com.pengxh.kt.lite.extensions.dp2px +import kotlin.math.cos +import kotlin.math.sin + + +class RadarScanView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { + + private val kTag = "RadarScanView" + + //View边框线条颜色 + private val borderColor: Int + + //View边框线条粗细 + private val border: Int + + //同心圆数量 + private val circleCount: Int + + //最外层圆半径 + private var radius: Int + + //需要渲染的数据点集合 + private val points = ArrayList() + + //View中心X坐标 + private var centerX = 0f + + //View中心Y坐标 + private var centerY = 0f + + //雷达扫描角度步长 + private var degrees = 0f + + private lateinit var borderPaint: Paint + private lateinit var shaderPaint: Paint + private lateinit var dataPaint: Paint + + //雷达扫描线后面的渐变梯度 + private lateinit var sweepGradient: SweepGradient + + //雷达旋转矩阵 + private lateinit var matrix: Matrix + + init { + val type = context.obtainStyledAttributes(attrs, R.styleable.RadarScanView) + borderColor = type.getColor(R.styleable.RadarScanView_radar_borderColor, Color.GRAY) + border = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_border, 1) + circleCount = type.getInt(R.styleable.RadarScanView_radar_circleCount, 4) + radius = type.getDimensionPixelOffset(R.styleable.RadarScanView_radar_radius, 150) + type.recycle() + + initPaint() + + //控制转动 + postDelayed(object : Runnable { + override fun run() { + degrees++ + //为矩阵设置旋转坐标,顺时针。因为翻转过坐标轴,所以需要- + matrix.setRotate(-degrees, 0f, 0f) + + invalidate() + if (degrees == 360f) { + degrees = 0f + } + + //周期10ms + postDelayed(this, 10) + } + //延迟100ms启动 + }, 100) + } + + private fun initPaint() { + borderPaint = Paint() + borderPaint.color = borderColor + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = border.toFloat() + borderPaint.strokeCap = Paint.Cap.ROUND //圆头 + borderPaint.isAntiAlias = true + + //扫描线画笔 + shaderPaint = Paint() + shaderPaint.isAntiAlias = true + shaderPaint.style = Paint.Style.FILL + sweepGradient = SweepGradient(0f, 0f, borderColor, Color.TRANSPARENT) + shaderPaint.shader = sweepGradient + + //数据点画笔 + dataPaint = Paint() + dataPaint.color = borderColor + dataPaint.isAntiAlias = true + dataPaint.style = Paint.Style.FILL + + //矩阵 + matrix = Matrix() + } + + //计算出中心位置,便于定位 + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + centerX = (w shr 1).toFloat() + centerY = (h shr 1).toFloat() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + /** + * 画布移到中心位置,方便绘制一系列图形 + */ + canvas.translate(centerX, centerY) + /** + * 上下翻转画布,因为手机等设备Y轴和生活中的坐标轴Y轴是反的 + * */ + canvas.scale(1f, -1f) + + //每道同心圆的半径差 + var tempR = radius + val deltaR = tempR / circleCount + for (i in 0..circleCount) { + canvas.drawCircle(0f, 0f, tempR.toFloat(), borderPaint) + tempR -= deltaR + } + + //画十字交叉线 + canvas.drawLine(0f, -radius.toFloat(), 0f, radius.toFloat(), borderPaint) + canvas.drawLine(-radius.toFloat(), 0f, radius.toFloat(), 0f, borderPaint) + + //画数据点 + points.forEach { + canvas.drawCircle(it.x, it.y, 10f, dataPaint) + } + + //关联矩阵 + canvas.concat(matrix) + canvas.drawCircle(0f, 0f, radius.toFloat(), shaderPaint) + } + + /** + * 数据点 + * @param dataPoints 数据点集合 + * */ + fun renderPointData(dataPoints: ArrayList) { + dataPoints.forEach { + val result = recursionAngle(it.angle) + //转为弧度 + val dataAngle = (result * Math.PI / 180).toFloat() + val dataDistance = recursionDistance(it.distance.dp2px(context).toFloat()) + + //计算实际圆心坐标 + val x = dataDistance * cos(dataAngle) + val y = dataDistance * sin(dataAngle) + + points.add(PointF(x, y)) + } + } + + /** + * 数据点 + * @param angle 数据点和圆心的方位角 + * @param distance 数据点和圆心的相对距离 + * */ + data class DataPoint(val angle: Float, val distance: Float) + + /** + * 递归计算周期性角度 + * */ + private fun recursionAngle(angle: Float): Float { + return if (angle < -360) { + recursionAngle(angle + 360) + } else if (angle > 360) { + recursionAngle(angle - 360) + } else { + angle + } + } + + /** + * 递归计算周期性距离 + * */ + private fun recursionDistance(distance: Float): Float { + return if (distance <= 0) { + 0f + } else if (distance >= radius) { + radius.toFloat() + } else { + distance + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_search_marker_new.xml b/app/src/main/res/layout/dialog_search_marker_new.xml index 3404a43..0ea108e 100644 --- a/app/src/main/res/layout/dialog_search_marker_new.xml +++ b/app/src/main/res/layout/dialog_search_marker_new.xml @@ -1,16 +1,18 @@ - + android:background="@mipmap/bg_search_label" + android:gravity="center_horizontal" + android:orientation="vertical"> - + @@ -104,8 +105,6 @@ android:id="@+id/buttonLayout" android:layout_width="320dp" android:layout_height="wrap_content" - android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/dp_10" android:layout_marginBottom="@dimen/dp_30" android:gravity="center_horizontal"> @@ -137,8 +136,4 @@ android:textColor="#CCCCCC" android:textSize="@dimen/sp_22" /> - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..1ddfbed --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file