1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Android】Composeの罠:デザインの指定が思い通りにならない

Posted at

Paddingが思い通りにならない

今回はJetpack Composeの罠について。
UIを作成するときにComposeを使って書いているのですが、そのときにpaddingの設定がうまくいかず困ったケースを挙げてみます。

TextFeid

ユーザーに文字を入力させたいとき、手っ取り早いのはTextFeildを使うことだと思います。

@Composable
private fun EditTextField() {
    var text by remember { mutableStateOf("") }
    
    TextField(
        value = text,
        onValueChange = { newText -> text = newText },
        placeholder = { Text(text = "ここに入力してください", color = Color.Gray) },
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    )
}

しかし、TextFieldを使うとTextFeildの外枠と実際に入力された文字が入るエリアのpaddingが固定されてしまっていて、TextFieldの外側から操作することができません。

例えばデザイナーさんから、TextFeildの外枠の位置から文字が入るようにしてほしいという指示があった場合は、このままでは対応できません。

そんな時は独自で用意するしかありません。
こちらの記事でも説明されているように、TextFieldの実装の中身を踏襲しつつ、paddingを外側から調整できるようにします。
ついでにデフォルトのフォントサイズなども扱いやすいように決めてしまいましょう。

// 内部のPaddingを調整できるようにcontentPaddingを引数に用意
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomTextField(
    modifier: Modifier = Modifier,
    value: String,
    onValueChange: (String) -> Unit,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = TextStyle(
        color = Color.Black,
        fontSize = 14.fontDp
    ),
    cursorColor: Brush = SolidColor(MaterialTheme.colors.secondaryVariant),
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    prefix: @Composable (() -> Unit)? = null,
    suffix: @Composable (() -> Unit)? = null,
    supportingText: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = true,
    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
    minLines: Int = 1,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    contentPadding: PaddingValues = TextFieldDefaults.contentPaddingWithLabel(
        0.dp,
        0.dp,
        0.dp,
        0.dp
    ),
    shape: Shape = TextFieldDefaults.shape,
    colors: TextFieldColors = TextFieldDefaults.colors(
        unfocusedContainerColor = Color.Transparent,
        focusedContainerColor = Color.Transparent,
        focusedIndicatorColor = MaterialTheme.colors.secondaryVariant,
        unfocusedIndicatorColor = MaterialTheme.colors.secondaryVariant,
    ),
) {
    BasicTextField(
        value = value,
        modifier = modifier
            .fillMaxWidth()
            .defaultMinSize(minHeight = 0.dp),
        onValueChange = { onValueChange(it) },
        enabled = enabled,
        readOnly = readOnly,
        textStyle = textStyle,
        cursorBrush = cursorColor,
        visualTransformation = visualTransformation,
        keyboardOptions = keyboardOptions,
        keyboardActions = keyboardActions,
        interactionSource = interactionSource,
        singleLine = singleLine,
        maxLines = maxLines,
        minLines = minLines,
        decorationBox = @Composable { innerTextField ->
            TextFieldDefaults.DecorationBox(
                value = value,
                visualTransformation = visualTransformation,
                innerTextField = innerTextField,
                placeholder = placeholder,
                label = label,
                leadingIcon = leadingIcon,
                trailingIcon = trailingIcon,
                prefix = prefix,
                suffix = suffix,
                supportingText = supportingText,
                shape = shape,
                singleLine = singleLine,
                enabled = enabled,
                isError = isError,
                interactionSource = interactionSource,
                colors = colors,
                contentPadding = contentPadding, // 内部のpadding
            )
        }
    )
}
@Composable
private fun EditTextField() {
    var text by remember { mutableStateOf("") }
    
    CustomEditTextField(
        value = text,
        onValueChange = { newText -> text = newText },
        placeholder = { Text(text = "ここに入力してください", color = Color.Gray) },
        contentPadding = PaddingValues(0.dp,10.dp,0.dp,10.dp),
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
    )
}

これで内部のpaddingが調整できるようになりました。
内部paddingのtop, bottom, start, end を個別で指定することもできるようになって使い勝手が上がったと思います(元々この形で実装していてほしい...)。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?