Skip to content

Commit

Permalink
Handle relative size using GeometryReader
Browse files Browse the repository at this point in the history
  • Loading branch information
paul1893 committed Jan 11, 2025
1 parent 14b521e commit 47c147a
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
9 changes: 4 additions & 5 deletions Sources/MarkdownUI/Utility/InlineNode+RawImageData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,15 @@ extension InlineNode {
/// - `{width=50px height=100px}`
/// - `{height=50px width=100px}`
/// - `{width=50%}`
/// - `{height=50%}`
/// - `{width=50% height=100%}`
/// - `{height=50% width=100%}`
///
/// - Note: Relative height is not supported
struct MarkdownImageSize {
let value: Value

enum Value {
/// Represents a fixed value size:`.fixed(width, height)`
/// Represents a fixed value size: `.fixed(width, height)`
case fixed(CGFloat?, CGFloat?)
/// Represents a relative value size: `.relative(proportionalWidth, proportionalHeight)`
/// Represents a relative value size: `.relative(relativeWidth, relativeHeight)`
case relative(CGFloat, CGFloat)
}
}
40 changes: 34 additions & 6 deletions Sources/MarkdownUI/Views/Inlines/ImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,50 @@ extension View {
private struct ImageViewFrameModifier: ViewModifier {
let size: MarkdownImageSize?

@State private var currentSize: CGSize = .zero

func body(content: Content) -> some View {
if let size {
switch size.value {
case .fixed(let width, let height):
content.frame(width: width, height: height)
content
.frame(width: width, height: height)
case .relative(let wRatio, _):
if #available(iOS 17.0, *) {
content
// .containerRelativeFrame(.vertical) { height, _ in height * hRatio }
.containerRelativeFrame(.horizontal) { width, _ in width * wRatio }
} else {
ZStack(alignment: .leading) {
/// Track the full content width.
GeometryReader { metrics in
content
.preference(key: BoundsPreferenceKey.self, value: metrics.frame(in: .global).size)
}
.opacity(0.0)

/// Draw the content applying relative width. Relative height is not handled.
content
.frame(
width: currentSize.width * wRatio
)
}
.onPreferenceChange(BoundsPreferenceKey.self) { newValue in
/// Avoid recursive loop that could happens
/// https://developer.apple.com/videos/play/wwdc2022/10056/?time=1107
if Int(currentSize.width) == Int(newValue.width),
Int(currentSize.height) == Int(newValue.height) {
return
}

self.currentSize = newValue
}
}
} else {
content
}
}
}

private struct BoundsPreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero

static func reduce(value: inout Value, nextValue: () -> Value) {
value = nextValue()
}
}

0 comments on commit 47c147a

Please sign in to comment.