@@ -2,34 +2,43 @@ package com.smarttoolfactory.image.zoom
22
33import androidx.compose.foundation.border
44import androidx.compose.foundation.layout.Box
5+ import androidx.compose.foundation.layout.fillMaxSize
56import androidx.compose.runtime.Composable
67import androidx.compose.ui.Alignment
78import androidx.compose.ui.Modifier
89import androidx.compose.ui.graphics.Color
10+ import androidx.compose.ui.layout.Measurable
11+ import androidx.compose.ui.layout.Placeable
12+ import androidx.compose.ui.layout.SubcomposeLayout
913import androidx.compose.ui.platform.LocalDensity
14+ import androidx.compose.ui.unit.Constraints
1015import androidx.compose.ui.unit.DpSize
1116import androidx.compose.ui.unit.dp
12- import com.smarttoolfactory.image.DimensionSubcomposeLayout
17+ import com.smarttoolfactory.image.SlotsEnum
1318
19+
20+ /* *
21+ * Layout that can zoom, rotate, pan its content with fling and moving back to bounds animation.
22+ */
1423@Composable
1524fun AnimatedZoomLayout (
1625 modifier : Modifier = Modifier ,
1726 content : @Composable () -> Unit
1827) {
1928
20- val density = LocalDensity .current
21-
22- DimensionSubcomposeLayout (
23- placeMainContent = false ,
29+ AnimatedZoomSubcomposeLayout (
30+ modifier = modifier,
2431 mainContent = { content() }
2532 ) {
2633 Box (
27- modifier
34+ Modifier
35+ .fillMaxSize()
2836 .border(5 .dp, Color .Red )
2937 .animatedZoom(
3038 animatedZoomState = rememberAnimatedZoomState(
3139 minZoom = .5f ,
32- maxZoom = 30f
40+ maxZoom = 30f ,
41+ contentSize = it
3342 ),
3443 ),
3544 contentAlignment = Alignment .Center
@@ -39,25 +48,55 @@ fun AnimatedZoomLayout(
3948 }
4049}
4150
51+ /* *
52+ * SubcomposeLayout for getting dimensions of [mainContent] while laying out with [modifier]
53+ * Use of this layout is suitable when size of parent doesn't match content
54+ * and size [mainContent] is required inside [dependentContent] to use [mainContent] size
55+ * as reference or dimensions for child composables inside [dependentContent].
56+ *
57+ */
4258@Composable
43- fun AnimatedZoomLayout2 (
59+ private fun AnimatedZoomSubcomposeLayout (
4460 modifier : Modifier = Modifier ,
45- content : @Composable () -> Unit
61+ mainContent : @Composable () -> Unit ,
62+ dependentContent : @Composable (DpSize ) -> Unit
4663) {
4764
48- Box (
49- modifier
50- .border(4 .dp, Color .Red )
51- .animatedZoom(
52- animatedZoomState = rememberAnimatedZoomState(
53- minZoom = .5f ,
54- maxZoom = 30f ,
55- contentSize = DpSize (200 .dp, 200 .dp)
56- )
57- ),
58- contentAlignment = Alignment .Center
59- ) {
60- content()
61- }
65+ val density = LocalDensity .current
66+
67+ SubcomposeLayout (
68+ modifier = modifier
69+ ) { constraints: Constraints ->
70+
71+ // Subcompose(compose only a section) main content and get Placeable
72+ val mainPlaceables: List <Placeable > = subcompose(SlotsEnum .Main , mainContent)
73+ .map {
74+ it.measure(constraints.copy(minWidth = 0 , minHeight = 0 ))
75+ }
76+
77+ // Get max width and height of main component
78+ var maxWidth = 0
79+ var maxHeight = 0
6280
63- }
81+ mainPlaceables.forEach { placeable: Placeable ->
82+ maxWidth + = placeable.width
83+ maxHeight = placeable.height
84+ }
85+
86+ val dependentPlaceables: List <Placeable > = subcompose(SlotsEnum .Dependent ) {
87+ val dpSize = density.run { DpSize (maxWidth.toDp(), maxHeight.toDp()) }
88+ dependentContent(dpSize)
89+ }
90+ .map { measurable: Measurable ->
91+ measurable.measure(constraints)
92+ }
93+
94+ layout(constraints.maxWidth, constraints.maxHeight) {
95+
96+
97+ dependentPlaceables.forEach { placeable: Placeable ->
98+ placeable.placeRelative(0 , 0 )
99+ }
100+ }
101+ }
102+ }
0 commit comments