/* 2023-01-24 File created by Kari Laitinen (c) naturalprogramming.com 2023-07-20 Modifications related to Material 3 use. This example demonstrates - RadioButton - KindRadioGroup from stackoverflow.com/questions/73248554/ - Canvas drawings This is an Android app made of this single file. If you want to test this app, create an Android Compose project with the project name SquareBallRectangleC and the package name shown below. Then, store this file to the folder where MainActivity.kt is and make the following change to AndroidManifest.xml: android:name=".SquareBallRectangleCActivity" Imports may need to be modified if a new Android/Compose version is used. Some 'warnings': - tab size in this file is 3 spaces - underscores may be used in the names invented by the programmer */ package squareball.rectanglec import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import squareball.rectanglec.ui.theme.SquareBallRectangleCTheme // I had to be clever enough to put some of the following imports myself // https://www.valueof.io/blog/jetpack-compose-canvas-custom-component-ondraw-drawscope import androidx.compose.foundation.Canvas import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButtonDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp @Composable fun KindRadioGroup( mItems: List, selected: String, setSelected: (selected: String) -> Unit, ) { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { mItems.forEach { item -> Row( verticalAlignment = Alignment.CenterVertically ) { RadioButton( selected = selected == item, onClick = { setSelected(item) }, enabled = true, colors = RadioButtonDefaults.colors( selectedColor = Color.Magenta ) ) // Using requiredWidth() for text made it possible to align the // items nicely also when the texts have varying lengths. Text(text = item, modifier = Modifier.padding(start = 8.dp).requiredWidth( 100.dp )) } } } } } class SquareBallRectangleCActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { SquareBallRectangleCTheme { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), color = Color( 0xFFEFEFEF ) ) { val configuration = LocalConfiguration.current //val context = LocalContext.current //val screen_height = configuration.screenHeightDp.dp val screenWidth = configuration.screenWidthDp.dp val kinds = listOf( "Square", "Ball", "Rectangle" ) val (selected, setSelected) = remember { mutableStateOf("Square" ) } Column( horizontalAlignment = Alignment.CenterHorizontally ) { // With a Box we can put Text and Canvas to the // same area on the screen. Box( modifier = Modifier.requiredWidth( screenWidth ).weight( 8F ) ) { // As the area reserved for Canvas is now determined // by the Box, we can just fill all that area. Canvas( modifier = Modifier.fillMaxSize() ) { //val canvasSize = size val canvasWidth = size.width val canvasHeight = size.height if ( selected == kinds[ 0 ] ) { drawRect( color = Color.Cyan, topLeft = Offset(x = canvasWidth / 4F, y = canvasHeight / 4F), size = Size( canvasWidth / 2F, canvasWidth/ 2F ) ) drawRect( color = Color.Black, topLeft = Offset(x = canvasWidth / 4F, y = canvasHeight / 4F), size = Size( canvasWidth / 2F, canvasWidth/ 2F ), style = Stroke( width = 4F ) ) } else if ( selected == kinds[ 1 ] ) { drawCircle( color = Color.Yellow, center = Offset( x = canvasWidth / 2, y = canvasHeight / 2 ), radius = size.minDimension / 4 ) drawCircle( color = Color.Black, center = Offset( x = canvasWidth / 2, y = canvasHeight / 2 ), radius = size.minDimension / 4, style = Stroke( width = 4F ) ) } else { drawRect( color = Color.Blue, topLeft = Offset(x = canvasWidth / 6F, y = canvasHeight / 4F), size = Size( canvasWidth / 1.5F, canvasWidth/ 2F ), style = Stroke( width = 12F ) ) } } } // end Box Box( modifier = Modifier .requiredWidth(screenWidth).weight(6F) ) { Column { KindRadioGroup( mItems = kinds, selected, setSelected ) Text( text = "Selected Option : $selected", textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), ) } } } // end Column } // end Surface } } } }