« Login UI in Android in Jetpack Compose
Create Sealed class InputType to tackel multiple types of inputs in 1 go
1sealed class InputType(2 val label: String,3 val icon: ImageVector,4 val keyboardOptions: KeyboardOptions,5 val visualTransformation: VisualTransformation6) {7 object Name : InputType(8 label = "Username",9 icon = Icons.Default.Person,10 keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),11 visualTransformation = VisualTransformation.None12 )1314 object Password : InputType(15 label = "Password",16 icon = Icons.Default.Lock,17 keyboardOptions = KeyboardOptions(18 imeAction = ImeAction.Done,19 keyboardType = KeyboardType.Password20 ),21 visualTransformation = VisualTransformation.None22 )23}
Create generic type TextInput
1@Composable2fun TextInput(3 inputType: InputType,4 focusRequester: FocusRequester? = null,5 keyboardActions: KeyboardActions6) {78 var value by remember { mutableStateOf("") }910 TextField(11 value = value,12 onValueChange = { value = it },13 modifier = Modifier14 .fillMaxWidth()15 .focusOrder(focusRequester ?: FocusRequester()),16 leadingIcon = { Icon(imageVector = inputType.icon, null) },17 label = { Text(text = inputType.label) },18 shape = Shapes.small,19 colors = TextFieldDefaults.textFieldColors(20 backgroundColor = Color.White,21 focusedIndicatorColor = Color.Transparent,22 unfocusedIndicatorColor = Color.Transparent,23 disabledIndicatorColor = Color.Transparent24 ),25 singleLine = true,26 keyboardOptions = inputType.keyboardOptions,27 visualTransformation = inputType.visualTransformation,28 keyboardActions = keyboardActions29 )30}
Create couple of extension functions on the Context object
1private fun Context.doLogin() {2 Toast.makeText(3 this,4 "Something went wrong, try again later!",5 Toast.LENGTH_SHORT6 ).show()7}89private fun Context.buildExoPlayer(uri: Uri) =10 ExoPlayer.Builder(this).build().apply {11 setMediaItem(MediaItem.fromUri(uri))12 repeatMode = Player.REPEAT_MODE_ALL13 playWhenReady = true14 prepare()15 }1617private fun Context.buildPlayerView(exoPlayer: ExoPlayer) =18 StyledPlayerView(this).apply {19 player = exoPlayer20 layoutParams = FrameLayout.LayoutParams(21 ViewGroup.LayoutParams.MATCH_PARENT,22 ViewGroup.LayoutParams.MATCH_PARENT23 )24 useController = false25 resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM26 }
Final UI composable
1@Composable2fun Login(videoUri: Uri) {3 val context = LocalContext.current4 val exoPlayer = remember { context.buildExoPlayer(videoUri) }5 val passwordFocusRequester = FocusRequester()6 val focusManager = LocalFocusManager.current78 DisposableEffect(9 AndroidView(factory = { it.buildPlayerView(exoPlayer) }, modifier = Modifier.fillMaxSize())10 ) {11 onDispose {12 exoPlayer.release()13 }14 }1516 ProvideWindowInsets {17 Column(18 Modifier19 .navigationBarsWithImePadding()20 .padding(24.dp)21 .fillMaxSize(),22 verticalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.Bottom),23 horizontalAlignment = Alignment.CenterHorizontally24 ) {2526 Icon(27 painter = painterResource(id = R.drawable.logo),28 contentDescription = null,29 Modifier.size(80.dp),30 tint = Color.White31 )3233 TextInput(inputType = InputType.Name, keyboardActions = KeyboardActions(onNext = {34 passwordFocusRequester.requestFocus()35 }))3637 TextInput(inputType = InputType.Password, keyboardActions = KeyboardActions(onDone = {38 focusManager.clearFocus()39 context.doLogin()40 }), focusRequester = passwordFocusRequester)4142 Button(onClick = {43 context.doLogin()44 }, modifier = Modifier.fillMaxWidth()) {45 Text(text = "SIGN IN", Modifier.padding(vertical = 8.dp))46 }4748 Divider(49 color = Color.White.copy(alpha = 0.3f),50 thickness = 1.dp,51 modifier = Modifier.padding(top = 48.dp)52 )5354 Row(verticalAlignment = Alignment.CenterVertically) {55 Text(text = "Don't have and account", color = Color.White)56 TextButton(onClick = {}) {57 Text(text = "SIGN UP")58 }59 }60 }61 }62}
For full working code please visit