Skip to content

Instantly share code, notes, and snippets.

@ohmantics
Created February 13, 2024 03:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ohmantics/7b2b35dc0c442a575841cf8a94265bd1 to your computer and use it in GitHub Desktop.
Save ohmantics/7b2b35dc0c442a575841cf8a94265bd1 to your computer and use it in GitHub Desktop.
//
// 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