Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image alignment broken when using placholder and crossfade #2728

Open
davidschreiber opened this issue Dec 2, 2024 · 1 comment
Open

Image alignment broken when using placholder and crossfade #2728

davidschreiber opened this issue Dec 2, 2024 · 1 comment

Comments

@davidschreiber
Copy link

davidschreiber commented Dec 2, 2024

Describe the bug

When using AsyncImage to display an image using crossfade and a placeholder, the initial image alignment won't work.

To Reproduce
Here is a small demo activity that shows the issue with little effort:

/** package declaration and imports removed for brevity */

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        setContent {
            CoilPlaceholderAlignmentBugTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Column(
                        modifier = Modifier.padding(innerPadding)
                    ) {
                        DemoImage(crossfade = true)
                        DemoImage(crossfade = false)
                    }
                }
            }
        }
    }

    @Composable
    private fun DemoImage(crossfade: Boolean) {
        AsyncImage(
            model = ImageRequest.Builder(LocalContext.current)
                .data("https://fastly.picsum.photos/id/1027/512/512.jpg?hmac=kFBJYzp0Y88x_HGjxrDXixHRgspdPuIO0jIswHYahvY")
                .crossfade(crossfade)
                .build(),
            imageLoader = imageLoader,
            contentDescription = null,
            contentScale = ContentScale.Crop,
            // Note: Removing the placeholder image will also work around the alignment bug.
            placeholder = ColorPainter(Color.Red),
            alignment = Alignment.TopCenter,
            modifier = Modifier
                .aspectRatio(16 / 9f)
                .fillMaxSize(),
        )
    }
}

Here is the output. Note that both images actually use the top anchor, but the one with crossfading enabled ignores the anchor:

Screenshot_20241202_133319

Version
This was discovered using Version 2.7.0 of Coil for Compose, but is also reproducible using 3.0.4.

@davidschreiber
Copy link
Author

davidschreiber commented Dec 2, 2024

Okay, I figured out that if I manually specify to use a CrossfadeTransition with preferExactIntrinsicSize = true, it works - most likely an issue with me using a sizeless painter as placeholder:

@Composable
private fun DemoImage(crossfade: Boolean) {
    AsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data("https://fastly.picsum.photos/id/1027/512/512.jpg?hmac=kFBJYzp0Y88x_HGjxrDXixHRgspdPuIO0jIswHYahvY")
            .transitionFactory(
                if (crossfade) CrossfadeTransition.Factory(
                    durationMillis = 200,
                    preferExactIntrinsicSize = true
                )
                else Transition.Factory.NONE
            )
            .build(),
        imageLoader = imageLoader,
        contentDescription = null,
        contentScale = ContentScale.Crop,
        // Note: Removing the placeholder image will also work around the alignment bug.
        placeholder = ColorPainter(Color.Red),
        alignment = Alignment.TopCenter,
        modifier = Modifier
            .aspectRatio(16 / 9f)
            .fillMaxSize(),
    )
}

Is this intended behavior, or is it indeed considered a bug?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant