panpf / zoomimage

ZoomImage is an gesture zoom viewing of images library specially designed for Compose Multiplatform and Android View. Supported scale, pan, locate, rotation, and super-large image subsampling.
Apache License 2.0
330 stars 19 forks source link

Image not aligned after orientation change #41

Closed IacobIonut01 closed 3 months ago

IacobIonut01 commented 3 months ago

Describe the bug

The Image is not longer aligned to Center (for example) after an orientation change (rotate the phone) - however, it returns to the default Top-Start. After re-opening the page on the new orientation, the image loads fine, however, if it rotates again, moves back to the Top-Start alignment

Affected platforms

Affected components

Select of the components below:

Versions

Running Devices

Sample code

    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        SketchZoomAsyncImage(
            modifier = Modifier.fillMaxSize(),
            uri = media.uri.toString(),
            contentScale = ContentScale.Fit,
            contentDescription = null
        )
    }

Reproduction steps

Expected behavior

Screenshots

Screenshot_20240813_221546 Screenshot_20240813_221559 Screenshot_20240813_221610

Additional context

None.

Thanks for creating this library, completely full-fills my use-cases, but there's this small thing that delays me to release the version with your library instead of coil and telephoto

panpf commented 3 months ago
SketchZoomAsyncImage(
      modifier = Modifier.fillMaxSize(),
      uri = media.uri.toString(),
      contentScale = ContentScale.Fit,
      alignment = Alignemnt.Center,
      contentDescription = null
)

You can get rid of the Box and set the alignment directly using the alignment parameter of SketchZoomAsyncImage

IacobIonut01 commented 3 months ago

I need the box to overlay the blur and the normal image.

Even without the content alignment of the Box (but keeping the box layout as parent), it still behaves the same

panpf commented 3 months ago

Ok, let me look into the issue again. My plan is to release a new version this Friday which should fix this issue.

IacobIonut01 commented 3 months ago

Thanks! I'm looking forward to it

panpf commented 3 months ago

I have tried many times and still can't reproduce this problem. Can you create a simple complete project that can repeat this problem for me?

Here is my demonstration video

https://github.com/user-attachments/assets/d8dd7caa-ff41-4d20-9524-1c158536e9ec

IacobIonut01 commented 3 months ago

I have tried many times and still can't reproduce this problem. Can you create a simple complete project that can repeat this problem for me?

Here is my demonstration video

2024-08-14.23.18.57.mp4

I'll double check my project then I'll get back with a sample project

IacobIonut01 commented 3 months ago

This reproduces the issue

val key = Random.nextInt()
key(key) {
    SketchZoomAsyncImage(
        modifier = Modifier.fillMaxSize(),
        uri = "content://media/external/images/media/54",
        contentDescription = null
    )
}
IacobIonut01 commented 3 months ago

@panpf I have solved the issue!

The culprit: (AndroidManifest.xml) android:configChanges="orientation"

panpf commented 3 months ago

This reproduces the issue (while this is an extreme measure - having the key to constantly recompose the screen - something for sure it's wrong in my project if this happens)

val key = Random.nextInt()
key(key) {
    SketchZoomAsyncImage(
        modifier = Modifier.fillMaxSize(),
        uri = "content://media/external/images/media/54",
        contentDescription = null
    )
}

You are doing this wrong, please remove the random key, it will cause the SketchZoomAsyncImage component to load/destroy in a loop and never stop. You can either not set the key or use uri as the key.

You can see the image because there is a memory cache. After the second time, it is loaded from the memory cache, which will be very fast.

The default alignment of the image is TopStart. SketchZoomAsyncImage will calculate the offset based on the actual Alignment after the image is loaded successfully. Unfortunately, the SketchZoomAsyncImage component is destroyed before it can calculate the offset. This cycle repeats and results in the result you see now.

panpf commented 3 months ago

@panpf I have solved the issue!

The culprit: (AndroidManifest.xml) android:configChanges="orientation"

I have tested this and it does not cause this problem.

IacobIonut01 commented 3 months ago

@panpf I have solved the issue! The culprit: (AndroidManifest.xml) android:configChanges="orientation"

I have tested this and it does not cause this problem.

"keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"

Have you tried with the full set?

IacobIonut01 commented 3 months ago

This reproduces the issue (while this is an extreme measure - having the key to constantly recompose the screen - something for sure it's wrong in my project if this happens)

val key = Random.nextInt()
key(key) {
    SketchZoomAsyncImage(
        modifier = Modifier.fillMaxSize(),
        uri = "content://media/external/images/media/54",
        contentDescription = null
    )
}

You are doing this wrong, please remove the random key, it will cause the SketchZoomAsyncImage component to load/destroy in a loop and never stop. You can either not set the key or use uri as the key.

You can see the image because there is a memory cache. After the second time, it is loaded from the memory cache, which will be very fast.

The default alignment of the image is TopStart. SketchZoomAsyncImage will calculate the offset based on the actual Alignment after the image is loaded successfully. Unfortunately, the SketchZoomAsyncImage component is destroyed before it can calculate the offset. This cycle repeats and results in the result you see now.

Yeah I know, it was purely experimental.

panpf commented 3 months ago

I only tried orientation

IacobIonut01 commented 3 months ago

@panpf I have solved the issue! The culprit: (AndroidManifest.xml) android:configChanges="orientation"

I have tested this and it does not cause this problem.

"keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"

Have you tried with the full set?

Because removing the orientation flag from there it fixed the bug on my side

panpf commented 3 months ago

This is my example, I can't reproduce the problem

<application
        android:name="com.github.panpf.zoomimage.sample.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="com.github.panpf.zoomimage.sample.MainActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
class MainActivity : BaseActivity() {

    @OptIn(ExperimentalFoundationApi::class)
    @SuppressLint("RestrictedApi")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        EdgeToEdgeUtils.applyEdgeToEdge(/* window = */ window,/* edgeToEdgeEnabled = */ true)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            window.statusBarColor = Color.parseColor("#60000000")
        }
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
            window.navigationBarColor = Color.TRANSPARENT
        }

        setContent {
            HorizontalPager(
                state = rememberPagerState {
                    ResourceImages.values.size
                },
                modifier = Modifier.fillMaxSize()
            ) {
                SketchZoomAsyncImage(
                    uri = ResourceImages.values[it].uri,
                    contentDescription = "",
                    modifier = Modifier.fillMaxSize()
                )
            }
        }
    }
}
panpf commented 3 months ago

@IacobIonut01 Is there any new progress?

IacobIonut01 commented 3 months ago

I'll close the issue as I have not managed to isolate the issue using a sample project, just in my case it seems that only the orientation flag was causing issue in this specific case, If I manage to properly reproduce the issue with a clean sample app, I'll re-open it. Until then, thanks for helping me out with this amazing library

panpf commented 3 months ago

Thank you for your appreciation. If this library really helps you, I hope you can recommend it to others who need an image zoom library, because the more people use it, the better it will become.

IacobIonut01 commented 3 months ago

For sure!