Skip to content

Instantly share code, notes, and snippets.

@CraigSiemens
Last active February 18, 2021 09:44
Show Gist options
  • Save CraigSiemens/3ab49e4dc62190acce9f7b692526538d to your computer and use it in GitHub Desktop.
Save CraigSiemens/3ab49e4dc62190acce9f7b692526538d to your computer and use it in GitHub Desktop.
Modified version if AirplaneView that tries to more closely match the behaviour in AutoLayout. https://talk.objc.io/episodes/S01E241-swiftui-layout-challenge-1
//
// ContentView.swift
// Airplane
//
// Created by Chris Eidhof on 08.02.21.
//
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, World!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct WidthKey: PreferenceKey {
static let defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
extension View {
func measureWidth(_ f: @escaping (CGFloat) -> ()) -> some View {
overlay(GeometryReader { proxy in
Color.clear.preference(key: WidthKey.self, value: proxy.size.width)
}
.onPreferenceChange(WidthKey.self, perform: f))
}
}
struct AirplaneView: View {
var from: Text = Text("Berlin")
var to: Text = Text("San Francisco")
let airplaneIcon = Text("✈️")
let spacerWidth: CGFloat = 4
@State var proposedWidth: CGFloat = 0
@State var fromWidth: CGFloat = 0
@State var airplaneWidth: CGFloat = 0
@State var toWidth: CGFloat = 0
var labelWidth: CGFloat {
(proposedWidth - airplaneWidth - spacerWidth * 2) / 2
}
var shouldDrawOffCenter: Bool {
isFromTruncated != isToTruncated
}
var isFromTruncated: Bool {
fromWidth > labelWidth
}
var isToTruncated: Bool {
toWidth > labelWidth
}
var body: some View {
HStack(spacing: 0) {
if shouldDrawOffCenter {
from
if isFromTruncated {
Spacer(minLength: spacerWidth)
.frame(width: spacerWidth)
} else {
Spacer(minLength: spacerWidth)
}
airplaneIcon
if isToTruncated {
Spacer(minLength: spacerWidth)
.frame(width: spacerWidth)
} else {
Spacer(minLength: spacerWidth)
}
to
} else {
from
.frame(maxWidth: .infinity, alignment: .leading)
airplaneIcon
to
.frame(maxWidth: .infinity, alignment: .trailing)
}
}
.measureWidth { self.proposedWidth = $0 }
.background(HStack {
from.fixedSize().measureWidth { self.fromWidth = $0 }
airplaneIcon.fixedSize().measureWidth { self.airplaneWidth = $0 }
to.fixedSize().measureWidth { self.toWidth = $0 }
}.hidden())
.lineLimit(1)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
VStack(spacing: 20) {
AirplaneView().frame(width: 250)
AirplaneView().frame(width: 200)
AirplaneView().frame(width: 175)
AirplaneView().frame(width: 150)
AirplaneView().frame(width: 125)
AirplaneView().frame(width: 100)
AirplaneView().frame(width: 75)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment