How to start and stop animation in Jetpack Compose - kotlin

In Jetpack Compose I need to start rotating a Text, when it is clicked. A coroutine runs, and when it is done, the animation should stopped.
So far I have:
var isRotating by remember { mutableStateOf(false) }
val angle = animateFloatAsState(
targetValue = if (isRotating) 360f else 0f,
animationSpec = infiniteRepeatable(tween(2000, easing = LinearEasing))
)
Box(
modifier = Modifier
.graphicsLayer { rotationZ = angle.value }
.clickable {
isRotating = true
coroutineScope.launch {
doSlowProcess()
isRotating = false
}
}
) {
Text("START")
}
The text "START" should rotating until the "doSlowProcess" runs. It starts the rotation, but when it ends, it does not stop, just starts rotating in the other way, slower, and when reaches 0° it flips 180 degrees, and goes on. If I click it again it does the correct rotation, but at 0° jumps 90° ahead. I guess these "anomalies" would disappear, if the rotation stop when "isRotating" becomes false. How should I correctly start and stop the rotation?

You can use something different:
var isRotating by remember { mutableStateOf(false) }
val angle = remember {
Animatable(0f)
}
LaunchedEffect(isRotating) {
launch {
if (isRotating) {
angle.animateTo(
targetValue = 360f,
animationSpec = infiniteRepeatable(
tween(2000, easing = LinearEasing)
)
)
}
}
}

Related

ExoPlayer landscape mode Jetpack Compose

I have a jetpack compose app in which there's a video player. The app is forced to portrait orientation, except for the screen/composable containing the video player. That composable is forced to landscape because I want to display the videos in landscape.
When I navigate to the page containing the video player the app correctly changes the orientation to landscape, but as soon as the video starts playing it rotates back to portrait orientation.
Any help is greatly appreciated...
Here's the relevant code for my problem.
#Composable
fun LockScreenOrientation(orientation: Int) {
val context = LocalContext.current
DisposableEffect(Unit) {
val activity = context.findActivity() ?: return#DisposableEffect onDispose {}
val originalOrientation = activity.requestedOrientation
activity.requestedOrientation = orientation
onDispose {
// restore original orientation when view disappears
activity.requestedOrientation = originalOrientation
}
}
}
fun Context.findActivity(): Activity? = when (this) {
is Activity -> this
is ContextWrapper -> baseContext.findActivity()
else -> null
}
#Composable
fun VideoView() {
val exoPlayer = remember {
ExoPlayer.Builder(context)
.build()
.apply {
setMediaItem(
MediaItem.Builder()
.apply {
setUri("https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")
setMediaMetadata(
MediaMetadata.Builder()
.build()
)
}
.build()
)
prepare()
playWhenReady = true
}
}
DisposableEffect(
AndroidView(factory = {
PlayerView(context).apply {
player = exoPlayer
useController = false
layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
})
) {
onDispose { exoPlayer.release() }
}
}
#Composable
fun VideoScreen() {
LockScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
RakeVragenTheme {
Surface(
modifier = Modifier
.fillMaxSize()
color = Color.Black
) {
VideoView()
}
}
}

Jetpack compose custom shape with pie effect

I want to make a shape filling the circle according to given percentage. Since i suck at math I'm unable to achieve this with path Api of jetpack compose.
My custom class is looking like this:
class ProgressPie(val progress: Float) : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
): Outline {
val path = Path().apply {
addArc(
Rect(0f, 0f, size.width , size.height ),
-90f,
360f * progress
)
close()
}
return Outline.Generic(path)
}
}
and when the progress parameter changed the result should be looking like this.
You can use Canvas or Modifier.draWithContent to draw a pie chart.
Column(modifier=Modifier.padding(10.dp)) {
var progress by remember { mutableStateOf(0f) }
Box(
modifier = Modifier
.background(Color.White)
.fillMaxWidth()
.aspectRatio(1f)
.drawBehind {
drawCircle(Color.LightGray, style = Stroke(1.dp.toPx()))
drawArc(
Color.Blue,
startAngle = -90f,
sweepAngle = progress,
useCenter = true
)
}
)
Slider(
value = progress,
onValueChange = {
progress = it
},
valueRange = 0f..360f
)
}
You can use shape with remember to create new shape on progress change but the issue with Path and arc is it's not drawn from center.
val shape = remember(progress) {
GenericShape { size: Size, _: LayoutDirection ->
if( progress == 360f){
addOval(
Rect(0f, 0f, size.width, size.height)
)
}else {
moveTo(size.width/2f, size.height/2f)
arcTo(
Rect(0f, 0f, size.width, size.height),
-90f,
progress,
forceMoveTo = false
)
}
close()
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.clip(shape)
.background(Color.Blue)
.aspectRatio(1f)
)

How do you make the Enter key move focus in Kotlin Compose Desktop?

I am making a program with a lot of text fields that needs to shift focus once Enter is pressed. They are all set to single line. (It should go to the next text field, once Enter is pressed)
I was using a focus requester, but it turns out in windows this is not necessary. Removing it, I still was able to change focus with tab. Is there a way to make this work with Enter?
It works out of the box because all text fields are focusable by default. Read more about the topic in Tabbing navigation and keyboard focus.
You can use LocalFocusManager to move focus with custom events:
val focusManager = LocalFocusManager.current
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
.onKeyEvent {
if (it.key == Key.Enter && it.type == KeyEventType.KeyDown) {
focusManager.moveFocus(FocusDirection.Next)
true
} else {
false
}
}
) {
Column(
modifier = Modifier.padding(50.dp)
) {
for (x in 1..5) {
val text = remember { mutableStateOf("") }
OutlinedTextField(
value = text.value,
singleLine = true,
onValueChange = { text.value = it }
)
Spacer(modifier = Modifier.height(20.dp))
}
}
}

how to know position for component android jet-pack compose Kotlin

I found that function to drag and drop component like in my code simple image
but now i need to found the x and y axis for that image on screen
like for example when i move it to new position put the new position in variable
#Composable
fun ImgLatterMoving(painter: Painter,contentDescription: String) {
val offsetX = remember { mutableStateOf(0F) }
val offsetY = remember { mutableStateOf(0F) }
Box(
modifier = Modifier
.offset {
IntOffset(
x = offsetX.value.roundToInt(),
y = offsetY.value.roundToInt()
)
}
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consumeAllChanges()
offsetX.value += dragAmount.x
offsetY.value += dragAmount.y
}
}
.size(100.dp)
) {
Image(painter = painter,
contentDescription = contentDescription,
modifier = Modifier.clip(RoundedCornerShape(10.dp))
)
}
}

Compose for Desktop LazyRow/LazyColumn not scrolling with mouse click

For some reason LazyColumns do not scroll with a mouse click and move gesture. It only works with the mouse wheel so far. For LazyRows it is also not possible to scroll with the mouse wheel. It seems that lazy row is useless for Compose for desktop.
Are there any possiblities to enable a click and move gesture on LazyRow and LazyColum. And if not is it at least possible to enable to scroll through a LazyRow with the mouse wheel?
I used this minimal reproducible example to test the scrolling
#Composable
#Preview
fun App() {
var text by remember { mutableStateOf("Hello, World!") }
MaterialTheme {
LazyRow(modifier = Modifier.fillMaxSize()) {
repeat(100) {
item {
Text("Test Test Test Test $it ")
}
}
}
}
}
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
App()
}
}
This is the intended behavior.
All scrollable components (including LazyColumn) work (for now) only with mouse wheel scroll events on the desktop.The scrollable components should not respond to mouse drag/move events.
Here's a basic example of how you can add drag support to your components:
val scrollState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
LazyRow(
state = scrollState,
modifier = Modifier
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState { delta ->
coroutineScope.launch {
scrollState.scrollBy(-delta)
}
},
)
) {
items(100) {
Text("Test Test Test Test $it")
}
}