Last active
February 18, 2021 09:44
-
-
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
This file contains 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
// | |
// 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