Created
February 13, 2024 03:50
-
-
Save ohmantics/7b2b35dc0c442a575841cf8a94265bd1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// LargestSymbolView.swift | |
// | |
// Created by Alex Rosenberg on 1/24/24. | |
// | |
import SwiftUI | |
// This view modifier takes a list of SF Symbols systemImage names | |
// and lays out as the largest frame needed to hold any of those | |
// images. | |
extension View { | |
func frameForLargestSymbol(symbols: [String], | |
alignment: Alignment = .center, | |
font: Font? = nil, | |
scale: Image.Scale? = nil) -> some View { | |
modifier(LargestSymbolModifier(symbols: symbols, alignment: alignment, font: font, scale: scale)) | |
} | |
} | |
private struct LargestSymbolModifier: ViewModifier { | |
let symbols: [String] | |
let alignment: Alignment | |
var font: Font? | |
var scale: Image.Scale? | |
func body(content: Content) -> some View { | |
ZStack(alignment: alignment) { | |
content | |
LargestSymbolView(symbols: symbols, alignment: alignment, font: font, scale: scale) | |
} | |
} | |
} | |
extension View { | |
@ViewBuilder | |
func ifCondition<TrueContent: View>(_ condition: Bool, then trueContent: (Self) -> TrueContent) -> some View { | |
if condition { | |
trueContent(self) | |
} else { | |
self | |
} | |
} | |
} | |
private struct LargestSymbolView: View { | |
var symbols : [String] | |
var alignment: Alignment = .center | |
var font: Font? | |
var scale: Image.Scale? | |
@State private var itemSize = CGSize.zero | |
var body: some View { | |
ZStack(alignment: alignment) { | |
ForEach(Array(symbols), id: \.self) { item in | |
Image(systemName: item) | |
.ifCondition(font != nil) { image in | |
image.font(font) | |
} | |
.ifCondition(scale != nil) { image in | |
image.imageScale(scale.unsafelyUnwrapped) | |
} | |
.background(GeometryReader { | |
Color.clear.preference(key: ItemSize.self, | |
value: $0.frame(in: .local).size) | |
}) | |
.hidden() | |
} | |
}.onPreferenceChange(ItemSize.self) { | |
itemSize = $0 | |
//print("size is now \(itemSize.width),\(itemSize.height)") | |
} | |
} | |
} | |
private struct ItemSize: PreferenceKey { | |
typealias Value = CGSize | |
static var defaultValue: CGSize { .zero } | |
static func reduce(value: inout Value, nextValue: () -> Value) { | |
let next = nextValue() | |
value = CGSize(width: max(value.width,next.width), | |
height: max(value.height,next.height)) | |
} | |
} | |
#Preview { | |
LargestSymbolView(symbols: ["speaker.slash.fill", | |
"speaker.wave.1.fill", | |
"speaker.wave.2.fill", | |
"speaker.wave.3.fill"], | |
alignment: .leading) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment