diff --git a/README.md b/README.md index a232bffc..fd70c596 100644 --- a/README.md +++ b/README.md @@ -1471,6 +1471,17 @@ Support levels: + + 🟢 + +
+ .rotation3DEffect + +
+ + 🟢 diff --git a/Sources/SkipUI/SkipUI/Layout/Presentation.swift b/Sources/SkipUI/SkipUI/Layout/Presentation.swift index 82729710..f2855886 100644 --- a/Sources/SkipUI/SkipUI/Layout/Presentation.swift +++ b/Sources/SkipUI/SkipUI/Layout/Presentation.swift @@ -139,7 +139,7 @@ let overlayPresentationCornerRadius = 16.0 // Draw the drag handle and the presentation root content area below it androidx.compose.foundation.layout.Spacer(modifier: Modifier.height(inset - handleHeight - handlePadding)) Row(modifier: Modifier.fillMaxWidth(), horizontalArrangement: Arrangement.Center) { - Capsule().fill(Color.primary.opacity(0.2)).frame(width: 60.0, height: Double(handleHeight.value)).Compose(context: context) + Capsule().fill(Color.primary.opacity(0.4)).frame(width: 60.0, height: Double(handleHeight.value)).Compose(context: context) } androidx.compose.foundation.layout.Spacer(modifier: Modifier.height(handlePadding)) } else if !isEdgeToEdge { diff --git a/Sources/SkipUI/SkipUI/View/View.swift b/Sources/SkipUI/SkipUI/View/View.swift index 1b2ec258..80d11bdb 100644 --- a/Sources/SkipUI/SkipUI/View/View.swift +++ b/Sources/SkipUI/SkipUI/View/View.swift @@ -21,11 +21,13 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp #elseif canImport(CoreGraphics) @@ -917,9 +919,32 @@ extension View { #endif } - @available(*, unavailable) public func rotation3DEffect(_ angle: Angle, axis: (x: CGFloat, y: CGFloat, z: CGFloat), anchor: UnitPoint = .center, anchorZ: CGFloat = 0.0, perspective: CGFloat = 1.0) -> some View { + #if SKIP + return ComposeModifierView(targetView: self) { context in + let animatable = Float(angle.degrees).asAnimatable(context: context) + // Try to approximate SwiftUI's perspective adaptation to view size + let size = remember { mutableStateOf(IntSize.Zero) } + let dimension = max(size.value.width * axis.y, size.value.height * axis.x) + let distance = max(Float(0.1), Float(dimension / 65)) / Float(perspective) + context.modifier = context.modifier + .onGloballyPositioned { size.value = $0.size } + .graphicsLayer( + transformOrigin: TransformOrigin(pivotFractionX: Float(anchor.x), pivotFractionY: Float(anchor.y)), + rotationX: Float(axis.x) * animatable.value, + rotationY: Float(axis.y) * animatable.value, + rotationZ: Float(axis.z) * animatable.value, + cameraDistance: distance + ) + return ComposeResult.ok + } + #else return self + #endif + } + + public func rotation3DEffect(_ angle: Angle, axis: (x: Int, y: Int, z: Int), perspective: CGFloat = 1.0) -> some View { + return rotation3DEffect(angle, axis: (CGFloat(axis.x), CGFloat(axis.y), CGFloat(axis.z)), perspective: perspective) } @available(*, unavailable)