JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
14.85k stars 1.08k forks source link

Vertical Text Align Issue in iOS #4725

Closed dilip640 closed 2 weeks ago

dilip640 commented 2 weeks ago

Describe the bug Top and bottom padding is not same in iOS. When using background color with text, then content is misaligned.

Affected platforms

Versions

To Reproduce Steps and/or the code snippet to reproduce the behavior:

Text(
   text = it,
   modifier = Modifier.then(modifier)
       .background(tagData.bgColor ?: Color.Yellow, shape = RoundedCornerShape(12.dp))
       .padding(horizontal = 8.dp),
   color = tagData.color ?: Color.Black,
   fontSize = 12.sp
)

Expected behavior Top and bottom text padding should be same.

image

Screenshots image

gsrathoreniks commented 2 weeks ago

@dilip640 Have you tried using fontPadding ? Explanation and examples listed here : Article

dilip640 commented 2 weeks ago

@dilip640 Have you tried using fontPadding ? Explanation and examples listed here : Article

@gsrathoreniks This blog is specific to Android. I'm having issue in iOS. Also includeFontPadding is not available in compose-multiplatform.

gsrathoreniks commented 2 weeks ago

@dilip640 Try this one out, I used in kotlin multi-platform project only and it solved my issue. Pass this style to the text.

Note : It's not an issue/bug it's just that fonts have their own padding and stylings. Depending on platform's default they sometimes can look little out of balance as in this particular case. LineHeightStyle can be used to apply alignments and trim.

TextStyle(lineHeightStyle = LineHeightStyle(alignment = alignment, trim = trim))

dilip640 commented 2 weeks ago

@gsrathoreniks I know there are ways to remove the extra padding. But in multiplatform case the default should be right on each platform.

gsrathoreniks commented 2 weeks ago

maybe it's picking the platform default

igordmn commented 2 weeks ago

Full reproducer:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun App() {
    Text(
        text = "Text",
        modifier = Modifier
            .background(Color.Yellow, shape = RoundedCornerShape(12.dp))
            .padding(horizontal = 8.dp),
        fontSize = 12.sp,
        style = TextStyle.Default.copy(
            lineHeight = 100.sp,
            lineHeightStyle = LineHeightStyle(
                alignment = LineHeightStyle.Alignment.Center,
                trim = LineHeightStyle.Trim.None,
            )
        ),
    )
}

Android: image

Other platforms: image

As a solution, override lineHeightStyle:

        style = LocalTextStyle.current.copy(
            lineHeightStyle = LineHeightStyle(
                alignment = LineHeightStyle.Alignment.Center,
                trim = LineHeightStyle.Trim.Both,
            )
        ),
MatkovIvan commented 2 weeks ago

@igordmn it's by design, see https://issuetracker.google.com/issues/321872412

Android/other platforms don't have a diff during my tests. Centering highly depends on font's data/metrics. Different platforms use different font by default. To get equal positioning - use the same font (from resources for example) Screenshot 2023-11-09 at 11 53 39 Also see my explanation here: https://github.com/JetBrains/compose-multiplatform/issues/3453#issuecomment-1803686130

igordmn commented 2 weeks ago

Centering highly depends on font's data/metrics

In this case, yes, there is no issue.

Solution is either to use the same font or override lineHeightStyle.

Different default font on different systems is by design.

MatkovIvan commented 2 weeks ago

Rechecked this particular sample with default system fonts:

image

Full code is:


@Composable
fun App() {
    Row(Modifier.systemBarsPadding()) {
        androidx.compose.foundation.text.BasicText(
            text = "Declared",
            modifier = Modifier
                .background(Color.Yellow, shape = RoundedCornerShape(12.dp))
                .padding(horizontal = 8.dp),
            style = TextStyle(
                color = Color.Black,
                fontSize = 12.sp
            ),
        )
        androidx.compose.material3.Text(
            text = "Declared",
            modifier = Modifier
                .background(Color.Yellow, shape = RoundedCornerShape(12.dp))
                .padding(horizontal = 8.dp),
            style = TextStyle(
                color = Color.Black,
                fontSize = 12.sp
            ),
        )
    }
}

Regarding specifying only fontSize (without lineHeightStyle and lineHeightStyle) inside MaterialTheme, I'd follow Google's recommendation from the issue mentioned above:

To support non-standard text sizes, we encourage users to follow the Material design system and use a different type scale rather than changing the font size directly. Alternatively, users can overwrite the line height like so: style = LocalTextStyle.current.copy(lineHeight = TextUnit.Unspecified), or create a custom Typography entirely.

MatkovIvan commented 2 weeks ago

Also includeFontPadding is not available in compose-multiplatform.

and should not! See my explanation here: https://github.com/JetBrains/compose-multiplatform/issues/2477#issuecomment-1825716543