https://kotlinlang.org logo
#compose
Title
# compose
j

jasu

06/22/2022, 9:49 AM
How do I call methods of view in androidView?
Copy code
AndroidView(
                factory = {
                    CropImageView(it).apply {
                        setCenterMoveEnabled(true)
                        setSnapRadius(16f)
                        setBackgroundColor(Color.Black.toArgb())
                        with(density) {
                            layoutParams = ViewGroup.LayoutParams(maxWidth.roundToPx(), maxHeight.roundToPx())
                        }
                    }
                },
                update = { cropView ->
                    // how to call cropView.rotateImage(90)                                    }
            )
m

myanmarking

06/22/2022, 10:39 AM
you don’t. Compose is ‘reactive’. You don’t call methods, you observe changes. So, just observe a properly in your AndroidView composable, and compose will call update for you
j

jasu

06/22/2022, 10:41 AM
sorry, but idea itself seems abstract to me. I’m not able to understand how will it be updated automatically?
this is a crop view, it just holds imageView and outside this view there’s a button which triggers rotate on this image view. so how exactly does this work?
m

myanmarking

06/22/2022, 10:43 AM
just define a property and use it inside the update. Something like: val rotation by remember{ mutableStateOf(90) }
everytime you change that value, compose will automatically call ‘update’ for you
j

jasu

06/22/2022, 10:44 AM
okay, and what about crop? say there’s method on view called cropImageView#startCrop(). In this case how will it work?
m

myanmarking

06/22/2022, 10:46 AM
@Composable
fun MainComposable(){
var rotation by remember{mutableStateOf(90)}
MyAndroidView(rotation)
// somewhere around here, you have a lambda with a click
// just call rotation = otherValue
}
@Composable
fun MyAndroidView(rotation: Float){
AndroidView(
factory = {
CropImageView(it).apply {
setCenterMoveEnabled(true)
setSnapRadius(16f)
setBackgroundColor(Color.Black.toArgb())
with(density) {
layoutParams = ViewGroup.LayoutParams(maxWidth.roundToPx(), maxHeight.roundToPx())
}
}
},
update = { cropView ->
cropView.rotateImage(rotation)                                    }
)
}
j

jasu

06/22/2022, 10:47 AM
got it but can you please demonstrate for startCrop method?
m

myanmarking

06/22/2022, 10:47 AM
that is not an easy question. I’v actually never needed to do that. Let me check
I’m not sure about that. But one solution could be remembering the View, and then use effects to call methods on that view. Let me check an example
j

jasu

06/22/2022, 10:51 AM
umm, official doc doesn’t recommend remembering the view
m

myanmarking

06/22/2022, 10:52 AM
ya, i quite figured that out. But then how would you do it?
j

jasu

06/22/2022, 10:56 AM
yeh this is big question currently I’ve.
m

myanmarking

06/22/2022, 10:57 AM
You can try something like this (disclaimer, i have no idea if this would work or if it is the right approach, because if you have some unstable properties, you can get unwanted crops)
Copy code
enum class CropState {
    START,
    END,
    NONE
}

@Composable
fun MainComposable() {
    var rotation by remember {
        mutableStateOf(90f)
    }

    var scropState by remember {
        mutableStateOf(CropState.NONE)
    }

    MyAndroidView(
        rotation = rotation,
        cropState = scropState
    )
    
    // somewhere here updated rotation
    // somewhere here change your cropState
}

@Composable
fun MyAndroidView(
    modifier: Modifier = Modifier,
    rotation: Float,
    cropState: CropState
) {
    AndroidView(
        factory = { context ->
            // your view here
            View(context)
        },
        update = {
            // some property updated
            when (cropState) {
                CropState.START -> TODO()
                CropState.END -> TODO()
                CropState.NONE -> TODO()
            }
        },
        modifier = modifier
    )
}
j

jasu

06/22/2022, 11:00 AM
okay not sure it will what if I click on rotate multiple times, will it rotate everytime as state would be same RotateState.Start _better I increment a variable on click of rotate and I listen in update -> rotateNumber.let { cropView.ro_tate(90) }
m

myanmarking

06/22/2022, 11:02 AM
Initially, i would use a channel with events. But i am not sure how to handle them inside the View, because you need a scope. Again, you could remember the scope outside and use it inside (it would work i guess) - but i am not comfortable with that approach, neither with my previous one. Better wait for a more experienced response 😛
That’s actually a good question ;o
a

andrew

06/22/2022, 6:40 PM
You can remember the view, Google Maps does this, lol 😆
j

jasu

06/23/2022, 5:07 PM
shitttt
a

andrew

06/23/2022, 5:10 PM
Realistically, it'd be best to keep things as event based as possible, if you want to provide actions, you could make your compose children scoped kinda like how scoped modifiers work
update runs every recomposition to update based on internal composable state
You might want to keep your rotation as an argument or inside mutableState
then for rotation buttons for example, provide events that bubble up to the parent, keeping your state hoisted
Copy code
@Composable
fun CropView(
  centerMoveEnabled: Boolean = true,
  snapRadius: Float: 16F,
  rotation: Float = 0F,
  modifier: Modifier = Modifier,
) {
  val context = LocalContext.current
  val view = remember { CropImageView(context) }

  AndroidView(
    modifier = Modifier,
    factory = { view },
    update = { view ->
      view.setCenterMoveEnabled(centerMoveEnabled)
      view.setSnapRadius(snapRadius)
      view.rotateImage(rotation)

      // or if rotate is based on a delta
      // view.rotateImage(rotation - view.rotation)
    }
  )
}
threw this together in text edit real fast
Might not be perfect, but this should do the job
j

jasu

06/23/2022, 5:25 PM
right, got the idea. thanks man
11 Views