Я новичок в 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"
Это идея о том, как я хочу, чтобы мой слайдер выглядел. Идея полукруглого слайдера температуры Единственным отличием будет добавление цифр в крайнем левом нижнем углу ползунка, чтобы показать пользователю диапазон значений, и центральное число, показывающее текущее значение.
Не стесняйтесь задавать любые вопросы, если это необходимо, или просить дополнительный код. И извините, если мой английский немного хромает.
Обновлен текст вопроса, чтобы показать наглядный пример SemicircularSlider.
И в случае вашей ошибки убедитесь, что вы правильно добавили Compose в свой проект, проверьте свой файл build.gradle
, подробнее здесь. stackoverflow.com/questions/69234206/…
Ваш код (на удивление,
Прежде всего, установка 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. Это решение сработало, но осталось слайдер, который выглядит полукруглым, но занимает пространство круглого ползунка и может быть изменен, даже если его нет. касаясь области ползунка.
Можете ли вы показать нам на картинке, что вы представляете себе слайдер или полукруглый слайдер?