Search code examples
android-jetpack-composetextfield

Paste Field weirdly placed w/ BasicTextField (Jetpack Compose)


I have setup a normal BasicTextField in Jetpack Compose (1.4.2).

If i want to paste a text copied earlier the field appears in a weird spot (top left corner). How can i fix this ?

Update: Provided code for BasicTextField implementation.

@Composable
fun CustomTextField(
    value: String,
    placeholder: String,
    enabled: Boolean = true,
    loading: Boolean = false,
    keyboardType: KeyboardType,
    update: ((String) -> Unit)? = null
) {

    var focus by remember {
        mutableStateOf(false)
    }

    BasicTextField(
        value = value,
        onValueChange = { new ->
            update?.let {
                it(new)
            }
        },
        cursorBrush = SolidColor(Blue),
        textStyle = MaterialTheme.typography.bodyMedium,
        decorationBox = { inner ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(
                        start = 16.dp,
                        end = 16.dp
                    ),
                contentAlignment = Alignment.CenterStart
            ) {
                if (value.isEmpty()) {
                    Text(
                        text = placeholder,
                        style = MaterialTheme.typography.bodyMedium,
                        color = Blue_2
                    )
                } else {
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween,
                        modifier = Modifier
                            .fillMaxWidth()
                    ) {
                        inner()

                        if (loading) {
                            Box(
                                modifier = Modifier
                                    .padding(vertical = 24.dp, horizontal = 16.dp)
                                    .size(16.dp)
                            ) {
                                CircularProgressIndicator(
                                    color = Blue_6
                                )
                            }
                        }
                    }
                }
            }
        },
        visualTransformation = if (keyboardType == KeyboardType.Password) PasswordVisualTransformation() else VisualTransformation.None,
        keyboardOptions = KeyboardOptions(
            keyboardType = keyboardType
        ),
        enabled = enabled,
        modifier = Modifier
            .fillMaxWidth()
            .shadow(
                elevation = if (focus) 15.dp else 7.5.dp,
                shape = RoundedCornerShape(16.dp),
                clip = false,
                ambientColor = Blue_6,
                spotColor = Blue_6
            )
            .background(
                if (focus) Focused else Not_Focused,
                RoundedCornerShape(16.dp)
            )
            .height(60.dp)
            .onFocusChanged {
                focus = it.hasFocus
            },
        singleLine = true
    )
}

enter image description here


Solution

  • You should use Textfield's inner() function every-time

    The problem is with your placeholder statement, here are the details:

    if (value.isEmpty()) {
        Text(
            text = placeholder,
            style = MaterialTheme.typography.bodyMedium,
            color = Blue
        )
    } else {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.SpaceBetween,
            modifier = Modifier
                .fillMaxWidth()
        ) {
            //This inner function should not be a part of the value.isEmpty() condition
            inner()
        }
    }
    

    With if (value.isEmpty()) condition you are not implementing inner() textfield function. While your text is empty the textfield does not exist and paste menu appears at the origin of the coordinate axis (top left corner).

    Here is a properly working example for you:

    @Composable
    fun CustomTextField(
        value: String,
        placeholder: String,
        enabled: Boolean = true,
        loading: Boolean = false,
        keyboardType: KeyboardType,
        update: ((String) -> Unit)? = null
    ) {
    
        var focus by remember {
            mutableStateOf(false)
        }
    
        BasicTextField(
            value = value,
            onValueChange = { new ->
                update?.let {
                    it(new)
                }
            },
            cursorBrush = SolidColor(Blue),
            textStyle = MaterialTheme.typography.bodyMedium,
            decorationBox = { inner ->
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(
                            start = 16.dp,
                            end = 16.dp
                        ),
                    contentAlignment = Alignment.CenterStart
                ) {
                    inner()
    
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween,
                        modifier = Modifier
                            .fillMaxWidth()
                    ) {
    
                        if (loading) {
                            Box(
                                modifier = Modifier
                                    .padding(vertical = 24.dp, horizontal = 16.dp)
                                    .size(16.dp)
                            ) {
                                CircularProgressIndicator(
                                    color = Blue
                                )
                            }
                        }
                    }
                
                    if (value.isEmpty()) {
                        Text(
                            text = placeholder,
                            style = MaterialTheme.typography.bodyMedium,
                            color = Blue
                        )
                    }
                }
            },
            visualTransformation = if (keyboardType == KeyboardType.Password) PasswordVisualTransformation() else VisualTransformation.None,
            keyboardOptions = KeyboardOptions(
                keyboardType = keyboardType
            ),
            enabled = enabled,
            modifier = Modifier
                .fillMaxWidth()
                .shadow(
                    elevation = if (focus) 15.dp else 7.5.dp,
                    shape = RoundedCornerShape(16.dp),
                    clip = false,
                    ambientColor = Blue,
                    spotColor = Blue
                )
                .background(
                    if (focus) Color.Cyan else Color.Green,
                    RoundedCornerShape(16.dp)
                )
                .height(60.dp)
                .onFocusChanged {
                    focus = it.hasFocus
                },
            singleLine = true
        )
    }