Touch events are blocked by "empty space" in a composable Column

Viewed 815

I'm trying to use Jetpack Compose in an existing app. From following the recommendations of integrating Compose with an existing app, I'm using the ComposeView in my existing xml layout:

       <?xml version="1.0" encoding="utf-8"?>
       <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <org.rajawali3d.view.SurfaceView
                android:id="@+id/rajwaliSurface"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <androidx.compose.ui.platform.ComposeView
                android:id="@+id/my_composable"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true" />
        </RelativeLayout>

I am rendering the compose view over the SurfaceView which is used for displaying 3D graphics.

I'm using a composable function similar to this:

@Composable
fun MyComposable() {
    Col() {
       Card(Modifier.width(100.dp){
         Text("Row1")
       }
       Card(Modifier.width(400.dp){
         Text("Row2")
       }
    }
}

The problem is: touch events in the SurfaceView is not captured if they occur inside the "empty space" in the Col column, i.e. above Row2 to the right of Row1. It's worth mentioning that touching to the right of Row2 works fine. It seems like the touch events does not propagate through the rectangle spanned by ComposableView, even the parts that are "empty".

1 Answers

Explaination: You can click to the side of the Column because the view is smaller than the surface. The 'empty' space is filled by the col because the col is as wide as its Composables require. Therefore the widest composable is 400dp (Row2) which is now the width of the View.

You could forward/bubble it yourself. If you need the exact position of the click you could use the provided offset of Modifier.rawPressStartGestureFilter Documentation or you might find a better-suited option.

class MyFragment : Fragment() {

    private lateinit var binding: ExampleBinding
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = ExampleBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.myComposable.setContent {
            MyComposable(bubbleClick = { handleClickForSurface() })
        }
        binding.rajwaliSurface.setOnClickListener { 
            handleClickForSurface()
        }
    }
    
    private fun handleClickForSurface() {
        // Handle the click
    }

    companion object {
        @Composable
        fun MyComposable(bubbleClick: () -> Unit) {
            Column(Modifier.clickable(onClick = bubbleClick)) {
                Card(Modifier.width(100.dp)) {
                    Text("Row1")
                }
                Card(Modifier.width(400.dp)) {
                    Text("Row2")
                }
            }
        }
    }
}

Edit: Added Explanation

Related