Как создать полукруглый слайдер с помощью холста Jetpack Compose?

Я новичок в Android Studio, и мне нужно создать слайдер для просмотра данных, полученных Arduino через Wi-Fi (температура и освещенность). Я хочу иметь составной файл SemicircularSlider.kt, который будет получать значения Arduino и отображать их в диапазоне, который я установлю в файле Kotlin. Затем с помощью файла Kotlin я хочу добавить их в свой макет в моем XML-файле, как будто это еще одно представление или просто виджет, и изменить значения (например, цвет и диапазон ползунка) через XML.

Поскольку я новичок в Composable и Android Studio, я попробовал создать Composable с помощью

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp
import kotlin.math.PI
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin

@Composable
fun SemiCircularSlider(
    modifier: Modifier = Modifier,
    value: Float,
    onValueChange: (Float) -> Unit,
    colorStart: Color,
    colorEnd: Color
) {
    var angle by remember { mutableStateOf(0f) }

    Canvas(modifier = modifier
        .fillMaxSize()
        .padding(16.dp)
        .pointerInput(Unit) {
            detectDragGestures { change, _ ->
                val position = change.position
                val center = Offset((size.width / 2).toFloat(), (size.height / 2).toFloat())
                angle = ((atan2(position.y - center.y, position.x - center.x) * 180 / PI).toFloat() + 180) % 180
                onValueChange(angle)
            }
        }
    ) {
        val radius = size.minDimension / 2
        val arcRect = Rect(Offset(size.width / 2 - radius, size.height / 2 - radius), Size(radius * 2, radius * 2))

        drawArc(
            color = colorStart,
            startAngle = 180f,
            sweepAngle = angle,
            useCenter = false,
            style = Stroke(width = 20f),
            topLeft = arcRect.topLeft,
            size = arcRect.size
        )

        val thumbX = center.x + cos((angle - 180) * PI / 180).toFloat() * radius
        val thumbY = center.y + sin((angle - 180) * PI / 180).toFloat() * radius

        drawCircle(
            color = colorEnd,
            radius = 20f,
            center = Offset(thumbX, thumbY)
        )
    }
}

@Composable
fun MainControlScreen() {
    var temperature by remember { mutableStateOf(0f) }
    var light by remember { mutableStateOf(0f) }

    MaterialTheme {
        Column {
            Text("Temperature: ${temperature.toInt()}")
            SemiCircularSlider(
                value = temperature,
                onValueChange = { temperature = it },
                colorStart = Color(0xFFFF5722),
                colorEnd = Color(0xFFFFC107)
            )
            Spacer(modifier = Modifier.height(32.dp))
            Text("Light: ${light.toInt()}")
            SemiCircularSlider(
                value = light,
                onValueChange = { light = it },
                colorStart = Color(0xFF03A9F4),
                colorEnd = Color(0xFF4CAF50)
            )
        }
    }
}

Я не спрашивал все про подключение Arduino, потому что даже полукруглый слайдер на экране показать не могу. Это решение привело меня к ошибке "org.jetbrains.kotlin.backend.common.BackendException: Backend Internal error: Exception during IR lowering"

Это идея о том, как я хочу, чтобы мой слайдер выглядел. Идея полукруглого слайдера температуры Единственным отличием будет добавление цифр в крайнем левом нижнем углу ползунка, чтобы показать пользователю диапазон значений, и центральное число, показывающее текущее значение.

Не стесняйтесь задавать любые вопросы, если это необходимо, или просить дополнительный код. И извините, если мой английский немного хромает.

Можете ли вы показать нам на картинке, что вы представляете себе слайдер или полукруглый слайдер?

Yamin 12.07.2024 03:15

Обновлен текст вопроса, чтобы показать наглядный пример SemicircularSlider.

Joaquin Hazzi 12.07.2024 17:58

И в случае вашей ошибки убедитесь, что вы правильно добавили Compose в свой проект, проверьте свой файл build.gradle, подробнее здесь. stackoverflow.com/questions/69234206/…

Yamin 12.07.2024 19:13
1
3
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш код (на удивление,

Прежде всего, установка fillMaxSize() для Canvas в большинстве случаев является ошибкой. Я предпочитаю установить для него произвольный размер или установить его на часть ширины/высоты устройства, но ради простоты работы давайте просто установим для него произвольный размер.

Canvas(modifier = modifier
        .size(300.dp)

вместо:

Canvas(modifier = modifier
        .fillMaxSize()

Следующая проблема заключается в том, что ваш SemiCircularSlider не использует параметр value, который является основными данными для вашего ползунка/датчика.

var angle by remember { mutableFloatStateOf(value) }

вместо:

var angle by remember { mutableFloatStateOf(0f) }

Итак, исправление вышеуказанных проблем оставляет нам следующее:

Ваше решение сработало. Вот чего мне не хватало. Первое: совместимость Kotlin 2.0.0 с Jetpack Compose. Если бы я добавил это: buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion compose_version } Тогда так и было бы. Итак, я понизил версию Kotlin до версии 1.9.24. 2-й: использование fillMaxSize() для Canvas. 3-й: не использовать параметр value. Это решение сработало, но осталось слайдер, который выглядит полукруглым, но занимает пространство круглого ползунка и может быть изменен, даже если его нет. касаясь области ползунка.

Joaquin Hazzi 12.07.2024 19:51

Другие вопросы по теме