فهرست منبع

CustomMarkLayer适配高保真样式,图标数量和点击自适应,计算文字点击,从java文件转成kotlin文件

Frankensteinly 9 ماه پیش
والد
کامیت
a9eae682dc

+ 0 - 9
app/src/main/java/com/grkj/iscs/model/bo/CustomPoint.kt

@@ -1,9 +0,0 @@
-package com.grkj.iscs.model.bo
-
-import android.graphics.PointF
-
-data class CustomPoint(
-    var pos: PointF?,
-    var name: String = "",
-    var status: Int = 1
-)

+ 23 - 18
app/src/main/java/com/grkj/iscs/view/fragment/WorkshopFragment.kt

@@ -2,14 +2,17 @@ package com.grkj.iscs.view.fragment
 
 import android.graphics.Bitmap
 import android.graphics.BitmapFactory
+import android.graphics.PointF
 import android.widget.ImageView
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentWorkshopBinding
 import com.grkj.iscs.model.Constants
+import com.grkj.iscs.model.vo.ticket.WorkstationTicketListRespVO
 import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.view.base.BaseMvpFragment
 import com.grkj.iscs.view.iview.IWorkshopView
 import com.grkj.iscs.view.presenter.WorkshopPresenter
+import com.grkj.iscs.view.widget.CustomMarkLayer
 import com.onlylemi.mapview.library.MapViewListener
 import com.zhy.adapter.recyclerview.CommonAdapter
 import com.zhy.adapter.recyclerview.base.ViewHolder
@@ -22,6 +25,11 @@ class WorkshopFragment :
     BaseMvpFragment<IWorkshopView, WorkshopPresenter, FragmentWorkshopBinding>() {
 
     private lateinit var jobStatisticList: MutableList<JobStatistics>
+    private var markLayer: CustomMarkLayer? = null
+    private val mPointList = mutableListOf(
+        CustomPoint(PointF(600f, 260f), "R&R", 8, mutableListOf()),
+        CustomPoint(PointF(800f, 480f), "CCO", 7, mutableListOf())
+    )
 
     override val viewBinding: FragmentWorkshopBinding
         get() = FragmentWorkshopBinding.inflate(layoutInflater)
@@ -45,8 +53,6 @@ class WorkshopFragment :
             }
         }
 
-        initMap()
-
         refreshPage()
     }
 
@@ -58,7 +64,11 @@ class WorkshopFragment :
             jobStatisticList.forEach { itJob ->
                 itJob.count = it.count { it.ticketType == itJob.sopType.type.toString() }
             }
+            mPointList.forEach { itPoint ->
+                itPoint.ticketList = it.filter { it.workstationId?.toInt() == itPoint.workstationId }.toMutableList()
+            }
             mBinding?.rvStatistics?.adapter?.notifyDataSetChanged()
+            initMap()
         }
     }
 
@@ -74,22 +84,15 @@ class WorkshopFragment :
         mBinding?.mapview?.loadMap(bitmap)
         mBinding?.mapview?.setMapViewListener(object : MapViewListener {
             override fun onMapLoadSuccess() {
-//                val marks: List<PointF> = TestData.getMarks()
-//                val marksName: List<String> = TestData.getMarksName()
-//                val pointList = mutableListOf<CustomPoint>()
-//                if (marks.size == marksName.size) {
-//                    marks.forEachIndexed { index, pointF ->
-//                        pointList.add(CustomPoint(pointF, marksName[index], index % 3))
-//                    }
-//                }
-//                markLayer = CustomMarkLayer(mBinding?.mapview, pointList)
-//                markLayer?.setMarkIsClickListener(CustomMarkLayer.MarkIsClickListener { index, btnIndex ->
-//                    Toast.makeText(
-//                        applicationContext, marksName[index] + " is selected, btnIndex is " + btnIndex, Toast.LENGTH_SHORT
-//                    ).show()
-//                })
-//                mBinding?.mapview?.addLayer(markLayer)
-//                mBinding?.mapview?.refresh()
+                markLayer = CustomMarkLayer(mBinding?.mapview, mPointList)
+                markLayer?.setMarkIsClickListener(object : CustomMarkLayer.MarkIsClickListener {
+                    override fun markIsClick(index: Int, btnIndex: Int) {
+                        ToastUtils.tip(mPointList[index].name + " is selected, btnIndex is " + btnIndex)
+                    }
+
+                })
+                mBinding?.mapview?.addLayer(markLayer)
+                mBinding?.mapview?.refresh()
             }
 
             override fun onMapLoadFail() {
@@ -103,4 +106,6 @@ class WorkshopFragment :
     }
 
     data class JobStatistics(var sopType: Constants.SopType, var count: Int)
+
+    data class CustomPoint(val pos: PointF, val name: String, val workstationId: Int, var ticketList: MutableList<WorkstationTicketListRespVO>)
 }

+ 0 - 210
app/src/main/java/com/grkj/iscs/view/widget/CustomMarkLayer.java

@@ -1,210 +0,0 @@
-package com.grkj.iscs.view.widget;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PointF;
-import android.util.Pair;
-import android.view.MotionEvent;
-
-import com.grkj.iscs.R;
-import com.grkj.iscs.model.bo.CustomPoint;
-import com.onlylemi.mapview.library.MapView;
-import com.onlylemi.mapview.library.layer.MapBaseLayer;
-import com.onlylemi.mapview.library.utils.MapMath;
-
-import java.util.List;
-
-public class CustomMarkLayer extends MapBaseLayer {
-    private List<CustomPoint> pointList;
-    private MarkIsClickListener listener;
-    private Bitmap btn1;
-    private Bitmap btn2;
-    private Bitmap btn3;
-    private Bitmap bmpMarkTouch;
-    private float radiusMark;
-    private boolean isClickMark;
-    private int num;
-    private Paint paint;
-    private int btnIndex;
-    private float currentZoom;
-    private float currentDegree;
-
-    public CustomMarkLayer(MapView mapView) {
-        this(mapView, null);
-    }
-
-    public CustomMarkLayer(MapView mapView, List<CustomPoint> list) {
-        super(mapView);
-        isClickMark = false;
-        num = -1;
-        btnIndex = -1;
-        pointList = list;
-        initLayer();
-    }
-
-    private void initLayer() {
-        radiusMark = setValue(10.0F);
-        btn1 = BitmapFactory.decodeResource(mapView.getResources(), R.mipmap.icon1);
-        btn2 = BitmapFactory.decodeResource(mapView.getResources(), R.mipmap.icon2);
-        btn3 = BitmapFactory.decodeResource(mapView.getResources(), R.mipmap.icon3);
-        bmpMarkTouch = BitmapFactory.decodeResource(mapView.getResources(), R.mipmap.icon2);
-        paint = new Paint();
-        paint.setAntiAlias(true);
-        paint.setStyle(Paint.Style.FILL_AND_STROKE);
-    }
-
-    public void onTouch(MotionEvent event) {
-        if (pointList != null && !pointList.isEmpty()) {
-            float[] goal = mapView.convertMapXYToScreenXY(event.getX(), event.getY());
-
-            for (int i = 0; i < pointList.size(); ++i) {
-                // 按钮1
-//                if (MapMath.getDistanceBetweenTwoPoints(goal[0], goal[1],
-//                        pointList.get(i).getPos().x,
-//                        pointList.get(i).getPos().y
-//                ) <= btn1.getWidth() / 2 / currentZoom) {
-//                    num = i;
-//                    btnIndex = 1;
-//                    isClickMark = true;
-//                    break;
-//                }
-
-                // 按钮2
-                if (MapMath.getDistanceBetweenTwoPoints(
-                        goal[0], goal[1],
-//                        pointList.get(i).getPos().x - btn2.getWidth() / 2 / currentZoom,
-                        rotatePoint(pointList.get(i).getPos().x - btn2.getWidth() / 2 / currentZoom, pointList.get(i).getPos().y - btn2.getHeight() / currentZoom, pointList.get(i).getPos().x, pointList.get(i).getPos().y, currentDegree).first,
-                        rotatePoint(pointList.get(i).getPos().x - btn2.getWidth() / 2 / currentZoom, pointList.get(i).getPos().y - btn2.getHeight() / currentZoom, pointList.get(i).getPos().x, pointList.get(i).getPos().y, currentDegree).second
-                ) <= btn2.getWidth() / 2 / currentZoom) {
-                    num = i;
-                    btnIndex = 2;
-                    isClickMark = true;
-                    break;
-                }
-
-                // 按钮3
-                if (MapMath.getDistanceBetweenTwoPoints(goal[0], goal[1],
-                        rotatePoint(pointList.get(i).getPos().x + btn3.getWidth() / 2 / currentZoom, pointList.get(i).getPos().y - btn3.getHeight() / currentZoom, pointList.get(i).getPos().x, pointList.get(i).getPos().y, currentDegree).first,
-                        rotatePoint(pointList.get(i).getPos().x + btn3.getWidth() / 2 / currentZoom, pointList.get(i).getPos().y - btn3.getHeight() / currentZoom, pointList.get(i).getPos().x, pointList.get(i).getPos().y, currentDegree).second
-                ) <= btn3.getWidth() / 2 / currentZoom) {
-                    num = i;
-                    btnIndex = 3;
-                    isClickMark = true;
-                    break;
-                }
-
-                if (i == pointList.size() - 1) {
-                    isClickMark = false;
-                }
-            }
-
-            if (listener != null && isClickMark) {
-                listener.markIsClick(num, btnIndex);
-                mapView.refresh();
-            }
-        }
-
-    }
-
-    public void draw(Canvas canvas, Matrix currentMatrix, float currentZoom, float currentRotateDegrees) {
-        this.currentZoom = currentZoom;
-        currentDegree = 360 - currentRotateDegrees;
-        if (isVisible && pointList != null) {
-            canvas.save();
-            if (!pointList.isEmpty()) {
-                for (int i = 0; i < pointList.size(); ++i) {
-                    PointF mark = pointList.get(i).getPos();
-                    float[] goal = new float[]{mark.x, mark.y};
-                    currentMatrix.mapPoints(goal);
-
-                    // TODO 文字背景
-                    float width = paint.measureText(pointList.get(i).getName());
-                    paint.setColor(Color.parseColor("#FFBB86FC"));
-                    paint.setStyle(Paint.Style.FILL);
-                    paint.setStrokeWidth(1.0F);
-                    // 圆角矩形
-                    canvas.drawRoundRect(goal[0] - width / 2, goal[1] - radiusMark / 2.0F, goal[0] + width / 2, goal[1] + radiusMark / 2.0F, 10f, 10f, paint);
-
-
-                    paint.setColor(-16777216);
-                    paint.setTextSize(radiusMark);
-                    if ((double) mapView.getCurrentZoom() > 1.0 && pointList != null) {
-//                        canvas.drawText(pointList.get(i).getName(), goal[0] - radiusMark, goal[1] - radiusMark / 2.0F, paint);
-                        canvas.drawText(pointList.get(i).getName(), goal[0] - width / 2, goal[1] + radiusMark / 3.0F, paint);
-                    }
-
-                    // TODO 此处不需要按钮,用文字替换
-//                    if (pointList.get(i).getStatus() < 2) {
-//                        canvas.drawBitmap(btn1, goal[0] - (float)(btn1.getWidth() / 2), goal[1] - (float)(btn1.getHeight() / 2), paint);
-//                    }
-                    // TODO 根据状态绘制按钮
-                    if (pointList.get(i).getStatus() == 2) {
-                        canvas.drawBitmap(btn2, goal[0] - (float) (btn2.getWidth()), goal[1] - (float) (btn2.getHeight() / 2 * 3), paint);
-                    }
-                    // TODO 根据状态绘制按钮
-                    if (pointList.get(i).getStatus() == 3) {
-                        canvas.drawBitmap(btn3, goal[0], goal[1] - (float) (btn3.getHeight() / 2 * 3), paint);
-                    }
-                    canvas.drawCircle(goal[0], goal[1], 2, paint);
-                    if (i == num && isClickMark) {
-                        canvas.drawBitmap(bmpMarkTouch, goal[0] - (float) (bmpMarkTouch.getWidth() / 2), goal[1] - (float) bmpMarkTouch.getHeight(), paint);
-                    }
-                }
-            }
-
-            canvas.restore();
-        }
-
-    }
-
-    public Pair<Float, Float> rotatePoint(float oriX, float oriY, float desX, float desY, float rotateDegrees) {
-        // 将度数转换为弧度
-        double theta = Math.toRadians(rotateDegrees);
-
-        // 计算旋转后的坐标
-        double A_new_x = (oriX - desX) * Math.cos(theta) - (oriY - desY) * Math.sin(theta) + desX;
-        double A_new_y = (oriX - desX) * Math.sin(theta) + (oriY - desY) * Math.cos(theta) + desY;
-
-        return new Pair<>((float) A_new_x, (float) A_new_y);
-    }
-
-    public int getNum() {
-        return num;
-    }
-
-    public void setNum(int num) {
-        num = num;
-    }
-
-//    public List<PointF> getMarks() {
-//        return marks;
-//    }
-//
-//    public void setMarks(List<PointF> marks) {
-//        this.marks = marks;
-//    }
-//
-//    public List<String> getMarksName() {
-//        return marksName;
-//    }
-//
-//    public void setMarksName(List<String> marksName) {
-//        this.marksName = marksName;
-//    }
-
-    public boolean isClickMark() {
-        return isClickMark;
-    }
-
-    public void setMarkIsClickListener(MarkIsClickListener listener) {
-        this.listener = listener;
-    }
-
-    public interface MarkIsClickListener {
-        void markIsClick(int index, int btnIndex);
-    }
-}

+ 220 - 0
app/src/main/java/com/grkj/iscs/view/widget/CustomMarkLayer.kt

@@ -0,0 +1,220 @@
+package com.grkj.iscs.view.widget
+
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.util.Pair
+import android.view.MotionEvent
+import com.grkj.iscs.R
+import com.grkj.iscs.view.fragment.WorkshopFragment.CustomPoint
+import com.onlylemi.mapview.library.MapView
+import com.onlylemi.mapview.library.layer.MapBaseLayer
+import com.onlylemi.mapview.library.utils.MapMath
+import kotlin.math.cos
+import kotlin.math.sin
+
+class CustomMarkLayer @JvmOverloads constructor(
+    mapView: MapView?,
+    private var pointList: List<CustomPoint> = mutableListOf()
+) : MapBaseLayer(mapView) {
+    private var listener: MarkIsClickListener? = null
+    private var radiusMark = 0f
+    private var isClickMark: Boolean = false
+    private var num: Int
+    private lateinit var paint: Paint
+    private var btnIndex: Int
+    private var currentZoom = 0f
+    private var currentDegree = 0f
+    private lateinit var icon: Bitmap
+
+    init {
+        num = -1
+        btnIndex = -1
+        initLayer()
+    }
+
+    private fun initLayer() {
+        radiusMark = setValue(10.0f)
+        // TODO 图标待替换
+        icon = BitmapFactory.decodeResource(mapView.resources, R.mipmap.point_placeholder)
+        paint = Paint()
+        paint.isAntiAlias = true
+        paint.style = Paint.Style.FILL_AND_STROKE
+    }
+
+    override fun onTouch(event: MotionEvent) {
+        if (pointList.isNotEmpty()) {
+            val goal = mapView.convertMapXYToScreenXY(event.x, event.y)
+
+            for (i in pointList.indices) {
+                val list = pointList[i].ticketList
+                var continueOuterLoop = false // 双循环跳出标志变量
+
+                // 计算文字点击
+                val width = paint.measureText(pointList[i].name) / currentZoom
+
+                val left = pointList[i].pos.x - (width / 2 + radiusMark / 4.0f * 3) / currentZoom
+                val top = pointList[i].pos.y - radiusMark / 4.0f * 3 / currentZoom
+                val right = pointList[i].pos.x + (width / 2 + radiusMark / 4.0f * 3) / currentZoom
+                val bottom = pointList[i].pos.y + radiusMark / 4.0f * 3 / currentZoom
+
+                if (goal[0] > left && goal[0] < right && goal[1] > top && goal[1] < bottom) {
+                    num = i
+                    btnIndex = -1
+                    isClickMark = true
+                    break
+                }
+
+                // 计算图标点击
+                for (j in list.indices) {
+                    val ticketX = if (list.size % 2 == 0) { // 偶数个
+                        if (j + 1 <= list.size / 2) {
+                            pointList[i].pos.x - icon.width * (list.size / 2 - j - 0.5f) / currentZoom
+                        } else {
+                            pointList[i].pos.x + icon.width * (j - list.size / 2 + 0.5f) / currentZoom
+                        }
+                    } else {    // 奇数个
+                        if (j + 1 <= list.size / 2) {
+                            pointList[i].pos.x - icon.width * (list.size / 2) / currentZoom
+                        } else {
+                            pointList[i].pos.x + icon.width * (j - list.size / 2) / currentZoom
+                        }
+                    }
+                    val rotatedPoint = rotatePoint(
+                        ticketX,
+                        pointList[i].pos.y - icon.height / currentZoom,
+                        pointList[i].pos.x,
+                        pointList[i].pos.y,
+                        currentDegree
+                    )
+
+                    val distance = MapMath.getDistanceBetweenTwoPoints(
+                        goal[0], goal[1],
+                        rotatedPoint.first,
+                        rotatedPoint.second
+                    )
+
+                    if (distance <= icon.width / 2 / currentZoom) {
+                        num = i
+                        btnIndex = j
+                        isClickMark = true
+                        continueOuterLoop = true
+                        break
+                    }
+                }
+
+                // 跳出外层循环
+                if (continueOuterLoop) break
+
+                if (i == pointList.size - 1) {
+                    isClickMark = false
+                }
+            }
+
+            if (listener != null && isClickMark) {
+                listener!!.markIsClick(num, btnIndex)
+                mapView.refresh()
+            }
+        }
+    }
+
+    override fun draw(
+        canvas: Canvas,
+        currentMatrix: Matrix,
+        currentZoom: Float,
+        currentRotateDegrees: Float
+    ) {
+        this.currentZoom = currentZoom
+        currentDegree = 360 - currentRotateDegrees
+        if (isVisible) {
+            canvas.save()
+            if (pointList.isNotEmpty()) {
+                pointList.forEach { point ->
+                    val mark = point.pos
+                    val goal = floatArrayOf(mark.x, mark.y)
+                    currentMatrix.mapPoints(goal)
+
+                    // TODO 文字背景
+                    val width = paint.measureText(point.name)
+                    paint.color = Color.parseColor("#70b26f")
+                    paint.style = Paint.Style.FILL
+                    paint.strokeWidth = 1.0f
+                    // 圆角矩形
+                    canvas.drawRoundRect(
+                        goal[0] - width / 2 - radiusMark / 4.0f * 3,
+                        goal[1] - radiusMark / 4.0f * 3,
+                        goal[0] + width / 2 + radiusMark / 4.0f * 3,
+                        goal[1] + radiusMark / 4.0f * 3,
+                        10f,
+                        10f,
+                        paint
+                    )
+
+                    paint.color = -16777216
+                    paint.textSize = radiusMark
+                    if (mapView.currentZoom.toDouble() > 0.8) {
+                        canvas.drawText(
+                            point.name,
+                            goal[0] - width / 2,
+                            goal[1] + radiusMark / 3.0f,
+                            paint
+                        )
+                    }
+
+                    val list = point.ticketList
+                    if (list.isNotEmpty()) {
+                        for (j in list.indices) {
+                            canvas.drawBitmap(
+                                icon,
+                                // 偶数个
+                                if (list.size % 2 == 0) {
+                                    if (j + 1 <= list.size / 2) {
+                                        goal[0] - icon.width * (list.size / 2 - j)
+                                    } else {
+                                        goal[0] + icon.width * (j - list.size / 2)
+                                    }
+                                } else {    // 奇数个
+                                    if (j + 1 <= list.size / 2) {
+                                        goal[0] - icon.width * (list.size / 2 + 0.5f)
+                                    } else {
+                                        goal[0] + icon.width * (j - list.size / 2 - 0.5f)
+                                    }
+                                },
+                                goal[1] - icon.height / 2 * 3,
+                                paint
+                            )
+                        }
+                    }
+                    // TODO 定位点,仅调试用,不要显示
+//                    canvas.drawCircle(goal[0], goal[1], 2f, paint)
+                }
+            }
+
+            canvas.restore()
+        }
+    }
+
+    private fun rotatePoint(
+        oriX: Float, oriY: Float, desX: Float, desY: Float, rotateDegrees: Float
+    ): Pair<Float, Float> {
+        // 将度数转换为弧度
+        val theta = Math.toRadians(rotateDegrees.toDouble())
+
+        // 计算旋转后的坐标
+        val newX = (oriX - desX) * cos(theta) - (oriY - desY) * sin(theta) + desX
+        val newY = (oriX - desX) * sin(theta) + ((oriY - desY) * cos(theta)) + desY
+
+        return Pair(newX.toFloat(), newY.toFloat())
+    }
+
+    fun setMarkIsClickListener(listener: MarkIsClickListener?) {
+        this.listener = listener
+    }
+
+    interface MarkIsClickListener {
+        fun markIsClick(index: Int, btnIndex: Int)
+    }
+}

BIN
app/src/main/res/mipmap/icon1.png


BIN
app/src/main/res/mipmap/icon2.png


BIN
app/src/main/res/mipmap/icon3.png


BIN
app/src/main/res/mipmap/point_placeholder.png


+ 1 - 0
app/src/main/res/values/colors.xml

@@ -29,4 +29,5 @@
     <color name="common_btn_red_bg">#80FF0000</color>
     <color name="lock_status_unlocked">#99008000</color>
     <color name="lock_status_locked">#CCFF0000</color>
+    <color name="point_text_bg">#70b26f</color>
 </resources>