JetpackCompose 改变转换数据类型时Canvas的重组

问题描述 投票:0回答:0

我想在 floor(floorState) 改变时重新组合 floorMap。将所有路径加起来并给这条路径一个状态的变体是不好的,因为在下一步中我想让每个 roomPath 和对象都可以点击。

这是我的 Jetpack compose 代码,用于转换输入数据和绘制地图:

fun initMap(
    pointsList: List<Point>,
    pathsList: List<PathModel>,
    width: Float,
    height: Float
): PathsAndObjectsHolderForDrawing {
    val pathsAndObjects = PathsAndObjectsHolderForDrawing()
    clearPathsAndObjectsHolder(pathsAndObjects)

    val requiredPoints = pointsList.filter { isPointObject(it) || pathsList.any { path -> path.pathId == it.pathId } }.toSet()

    for (pathType in enumValues<PathType>()) {
        val pathsOfType = pathsList.filter { it.pathType == pathType }
        val paths = pathsOfType.map { pathModel ->
            val pointsForPath = requiredPoints.filter { it.pathId == pathModel.pathId }.sortedBy { it.inPathId }
            makePathFromPoints(pointsForPath, width, height)
        }

        when (pathType) {
            PathType.ELEVATOR -> pathsAndObjects.elevatorsPath.paths.addAll(paths)
            PathType.STAIRS -> pathsAndObjects.stairsPath.paths.addAll(paths)
            PathType.ROOM -> pathsAndObjects.roomsPath.paths.addAll(paths)
            PathType.OUTER_WALL -> pathsAndObjects.outerWallPath.paths.addAll(paths)
            PathType.INTERNAL_WALL -> pathsAndObjects.internalWallsPath.paths.addAll(paths)
            PathType.OTHER -> pathsAndObjects.othersPath.paths.addAll(paths)
        }
    }

    return pathsAndObjects
}

fun clearPathsAndObjectsHolder(paths: PathsAndObjectsHolderForDrawing) {
    paths.elevatorsPath.paths.clear()
    paths.stairsPath.paths.clear()
    paths.roomsPath.paths.clear()
    paths.outerWallPath.paths.clear()
    paths.internalWallsPath.paths.clear()
    paths.othersPath.paths.clear()
    paths.objects.objects.clear()
}

fun makePathFromPoints(points: List<Point>, width: Float, height: Float): Path {
    val path = Path()
    for ((index, point) in points.withIndex()){
        if (index == 0) path.moveTo(point.x * width, point.y * height)
        else {
            when (point.pointParameter) {
                PointParameter.LINE -> path.lineTo(point.x * width, point.y * height)
                PointParameter.BEZIER3 -> cubicBezierForThreePoints(listOf(points[index - 2], points[index - 1], points[index]), path, width, height)
                else -> Unit
            }
        }
    }
    return path
}

fun cubicBezierForThreePoints(points: List<Point>, path: Path, width: Float, height: Float){
    val secondPoint = Pair(points[0].x * width, ((points[1].y - points[0].y) * 4 / 3 + points[0].y) * height)
    val thirdPoint = Pair(points[2].x * width, ((points[1].y - points[2].y) * 4 / 3 + points[2].y) * height)
    val fourthPoint = Pair(points[2].x * width, points[2].y * height)
    path.cubicTo(secondPoint.first, secondPoint.second, thirdPoint.first, thirdPoint.second, fourthPoint.first, fourthPoint.second)
}

fun isPointObject(point: Point): Boolean = point.pointType == PointType.OBJECT

这里是让路。这是工作,但重组可能不会发生或可能会延迟发生。

@Composable
fun Map3(modifier: Modifier = Modifier,
        floorState: StateFlow<FloorState>
) {
    var pathsAndObjects: PathsAndObjectsHolderForDrawing = remember { PathsAndObjectsHolderForDrawing() }

//    val coroutineScope = CoroutineScope(Dispatchers.Default)


    val paint = Paint()
    paint.color = Color.Red
    paint.strokeWidth = 10f


    Canvas(
        modifier = modifier
            .aspectRatio(3 / 2f)
            .fillMaxSize()
    ) {
        val height = size.height
        val width = size.width

        Log.d("height", height.toString())

        floorState.let {
            pathsAndObjects = initMap(it.value.points, it.value.paths, width, height)
            Log.d("let", pathsAndObjects.objects.objects.size.toString())
            drawPoints(pathsAndObjects.objects.objects, PointMode.Points, Color.Red, 10f)
        }

    }
}

这里是 coroutineScope 内部可与 StateFlow.collectAsState 组合的方式。这是行不通的。

@Composable
fun Map(modifier: Modifier = Modifier,
        floorState: StateFlow<FloorState>
) {
    var pathsAndObjects = remember { PathsAndObjectsHolderForDrawing() }

    val coroutineScope = rememberCoroutineScope()

//    val floorState by floorState.collectAsState()

    val paint = Paint()
    paint.color = Color.Red
    paint.strokeWidth = 10f
    val block: MutableState<Canvas.() -> Unit> =
        remember { mutableStateOf( {drawPoints(PointMode.Points, listOf(Offset(450f, 450f)), paint) } ) }

    Canvas(
        modifier = modifier
            .aspectRatio(3 / 2f)
            .fillMaxSize()
    ) {
        val height = size.height
        val width = size.width
        val paint = Paint().apply {
                    style = PaintingStyle.Stroke
                    strokeWidth = 5f
                    color = Color.Black
                }
        drawIntoCanvas{
            coroutineScope.launch {
                floorState.collect {floorState ->
                    block.value = {
                        initMap(floorState.points, floorState.paths, width, height).also {pathsAndObjects ->
                        pathsAndObjects.roomsPath.paths.forEach{ path ->
                            drawPath(path, Color.Red)
                        }
                            drawPoints(pathsAndObjects.objects.objects,
                                PointMode.Points,
                                pathsAndObjects.objects.color
                            )

                        }
                }
                }
            }
            val a = block.value
            it.a()
        }
        }
    }

还在 drawIntoCanvas 中用 flow 尝试过。这是行不通的。

        coroutineScope.launch {
            floorState.collect {State ->
                initMap(floorState.value.points, floorState.value.paths, width, height)
            }
        }

            pathsAndObjects = initMap(floorState.value.points, floorState.value.paths, width, height)
            if (pathsAndObjects.elevatorsPath.paths.isNotEmpty()) {
                for (item in pathsAndObjects.elevatorsPath.paths) {
                    drawPath(item, Color.Green, style = Stroke(2.dp.toPx()))
                }
            }

            if (pathsAndObjects.stairsPath.paths.isNotEmpty()) {
                for (item in pathsAndObjects.stairsPath.paths) {
                    drawPath(item, Color.Green, style = Stroke(2.dp.toPx()))
                }
            }


            if (pathsAndObjects.roomsPath.paths.isNotEmpty()) {
                for (item in pathsAndObjects.roomsPath.paths) {
                    drawPath(item, Color.Green, style = Stroke(2.dp.toPx()))
                }
            }

            if (pathsAndObjects.outerWallPath.paths.isNotEmpty()) {
                for (item in pathsAndObjects.outerWallPath.paths) {
                    drawPath(item, Color.Green, style = Stroke(2.dp.toPx()))
                }
            }

            if (pathsAndObjects.internalWallsPath.paths.isNotEmpty()) {
                for (item in pathsAndObjects.internalWallsPath.paths) {
                    drawPath(item, Color.Green, style = Stroke(2.dp.toPx()))
                }
            }

            if (pathsAndObjects.othersPath.paths.isNotEmpty()) {
                for (item in pathsAndObjects.othersPath.paths) {
                    drawPath(item, Color.Green, style = Stroke(2.dp.toPx()))
                }
            }

            if (pathsAndObjects.objects.objects.isNotEmpty()) {
                Log.d("pointShouldBeDraw", "whyNot?")
                drawPoints(
                    pathsAndObjects.objects.objects,
                    pointMode = PointMode.Points,
                    color = Color.Red,
                    strokeWidth = 10f
                )
            }

这里是发射效果。这是行不通的。

@Composable
fun Map(modifier: Modifier = Modifier,
        floorState: StateFlow<FloorState>,
        configuration: Configuration,
        density: Density
) {
    val floorState = floorState.collectAsState()
    var pathsAndObjects: PathsAndObjectsHolderForDrawing = remember { initMap(floorState.value.points, floorState.value.paths,
        configuration.screenWidthDp.toFloat() * density.density,
        configuration.screenWidthDp.toFloat() * density.density
    ) }
    
    
    LaunchedEffect(floorState.value) {
        val floor = floorState.value
        pathsAndObjects = withContext(Dispatchers.Default) {
            initMap(floor.points, floor.paths,
                configuration.screenWidthDp.toFloat() * density.density,
                configuration.screenWidthDp.toFloat() * density.density
            )
        }
    }

    val paint = Paint()
    paint.color = Color.Red
    paint.strokeWidth = 10f
    val block: MutableState<Canvas.() -> Unit> =
        remember { mutableStateOf( {drawPoints(PointMode.Points, listOf(Offset(450f, 450f)), paint) } ) }

    Canvas(
        modifier = modifier
            .aspectRatio(3 / 2f)
            .fillMaxSize()
    ) {
        val height = size.height
        val width = size.width

        floorState.value.let {
            drawPoints(pathsAndObjects.objects.objects, PointMode.Points, Color.Red, 10f)
        }
    }
}

请建议我可以重构 Canvas 的方法,或者其他让我的逻辑正常工作的方法。

android android-jetpack-compose android-canvas android-jetpack-compose-canvas
© www.soinside.com 2019 - 2024. All rights reserved.