Created
April 20, 2022 12:37
-
-
Save Tiagoperes/02cb138c716153da2881ab219b9efa64 to your computer and use it in GitHub Desktop.
Layout examples in SwfitUI
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 | |
// layout-tests | |
// | |
// Created by Tiago Peres França on 15/04/22. | |
// | |
import SwiftUI | |
struct Example1: View { | |
var body: some View { | |
HStack(alignment: .top, spacing: 0) { | |
HStack() { Text("R") } | |
.frame(maxWidth: .infinity, maxHeight: 80, alignment: .topLeading) | |
.background(Color.red) | |
HStack() { Text("G") } | |
.frame(maxWidth: .infinity, maxHeight: 50, alignment: .topLeading) | |
.background(Color.green) | |
HStack() { Text("B") } | |
.frame(maxWidth: .infinity, maxHeight: 50, alignment: .topLeading) | |
.background(Color.blue) | |
} | |
.frame(maxWidth: .infinity) | |
.background(Color.gray) | |
} | |
} | |
struct Example2: View { | |
var body: some View { | |
HStack(spacing: 0) { | |
HStack() { Text("R") } | |
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | |
.background(Color.red) | |
.padding(.leading, 10) | |
HStack() { Text("G") } | |
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | |
.background(Color.green) | |
.padding(.leading, 10) | |
HStack() { Text("B") } | |
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | |
.background(Color.blue) | |
.padding(.leading, 10) | |
} | |
.frame(maxWidth: .infinity, maxHeight: 50) | |
.background(Color.gray) | |
} | |
} | |
struct Example3: View { | |
var body: some View { | |
HStack(spacing: 0) { | |
HStack() { Text("R") } | |
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | |
.padding(.leading, 10) | |
.background(Color.red) | |
HStack() { Text("G") } | |
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | |
.padding(.leading, 10) | |
.background(Color.green) | |
HStack() { Text("B") } | |
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) | |
.padding(.leading, 10) | |
.background(Color.blue) | |
} | |
.frame(maxWidth: .infinity, maxHeight: 50) | |
.background(Color.gray) | |
} | |
} | |
struct Example4: View { | |
var body: some View { | |
let flexSum = 4.0 | |
GeometryReader { geo in | |
HStack(spacing: 0) { | |
HStack() { Text("R") } | |
.frame(maxWidth: 2 * geo.size.width / flexSum, maxHeight: .infinity, alignment: .leading) | |
.background(Color.red) | |
HStack() { Text("G") } | |
.frame(maxWidth: geo.size.width / flexSum, maxHeight: .infinity, alignment: .leading) | |
.background(Color.green) | |
HStack() { Text("B") } | |
.frame(maxWidth: geo.size.width / flexSum, maxHeight: .infinity, alignment: .leading) | |
.background(Color.blue) | |
} | |
.frame(maxWidth: .infinity, maxHeight: 50) | |
.background(Color.gray) | |
} | |
} | |
} | |
struct Example5: View { | |
var body: some View { | |
HStack(alignment: .top, spacing: 0) { | |
HStack() { Text("R") } | |
.frame(maxWidth: .infinity, maxHeight: 50, alignment: .leading) | |
.background(Color.red) | |
.padding(.vertical, 10) | |
HStack() { Text("G") } | |
.frame(maxWidth: .infinity, maxHeight: 50, alignment: .leading) | |
.background(Color.green) | |
HStack() { Text("B") } | |
.frame(maxWidth: .infinity, maxHeight: 50, alignment: .leading) | |
.padding(.vertical, 10) | |
.background(Color.blue) | |
} | |
.frame(maxWidth: .infinity) | |
.background(Color.gray) | |
} | |
} | |
struct Example6: View { | |
var body: some View { | |
HStack(spacing: 0) { | |
HStack() { Text("Image") } | |
.frame(width: 100, height: 66) | |
.background(Color.red) | |
.padding(.trailing, 20) | |
HStack {} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background(Color.blue) | |
} | |
.frame(maxWidth: .infinity) | |
.background(Color.gray) | |
.fixedSize(horizontal: false, vertical: true) | |
} | |
} | |
struct Example7: View { | |
var body: some View { | |
ScrollView { | |
VStack(spacing: 0) { | |
VStack { | |
Text("flex-start") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .topLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("flex-end") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .topTrailing) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("center") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .top) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("space-around") | |
HStack(spacing: 0) { | |
Spacer(minLength: 0) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
Spacer(minLength: 0) | |
Spacer(minLength: 0) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
Spacer(minLength: 0) | |
} | |
.frame(width: 75, height: 75, alignment: .topLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("space-between") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
Spacer() | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .topLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("space-evenly") | |
HStack(spacing: 0) { | |
Spacer() | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
Spacer() | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
Spacer() | |
} | |
.frame(width: 75, height: 75, alignment: .topLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
} | |
} | |
} | |
} | |
struct Example8: View { | |
var body: some View { | |
VStack(spacing: 0) { | |
VStack { | |
Text("flex-start") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .topLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("flex-end") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .bottomLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("center") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25, height: 25) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .leading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
VStack { | |
Text("stretch") | |
HStack(spacing: 0) { | |
HStack {} | |
.frame(width: 25) | |
.frame(maxHeight: .infinity) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 25) | |
.frame(maxHeight: .infinity) | |
.background(Color.blue) | |
} | |
.frame(width: 75, height: 75, alignment: .topLeading) | |
.background(Color.gray) | |
.padding(.bottom, 10) | |
} | |
} | |
} | |
} | |
struct Example9: View { | |
var body: some View { | |
HStack(spacing: 0) { | |
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et ipsum eu nunc semper dapibus vitae id urna. Aenean fermentum purus vitae leo congue varius vel nec ligula. Ut feugiat consectetur augue mattis tempus. Curabitur a erat nec lectus convallis vestibulum. Pellentesque suscipit id tellus ac dapibus. Vivamus aliquam, urna eu ornare euismod, arcu purus vestibulum dolor, ac tempus ante metus mollis ipsum. Ut eget tellus mollis, efficitur sapien in, pulvinar neque.") | |
} | |
.frame(width: 300) | |
.background(Color.gray) | |
} | |
} | |
struct Example10: View { | |
var body: some View { | |
HStack(spacing: 0) { | |
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et ipsum eu nunc semper dapibus vitae id urna. Aenean fermentum purus vitae leo congue varius vel nec ligula. Ut feugiat consectetur augue mattis tempus. Curabitur a erat nec lectus convallis vestibulum. Pellentesque suscipit id tellus ac dapibus. Vivamus aliquam, urna eu ornare euismod, arcu purus vestibulum dolor, ac tempus ante metus mollis ipsum. Ut eget tellus mollis, efficitur sapien in, pulvinar neque.") | |
.fixedSize() | |
} | |
.frame(width: 300, alignment: .leading) | |
.clipped() | |
.background(Color.gray) | |
} | |
} | |
/* Example 11: | |
* https://www.fivestars.blog/articles/flexible-swiftui/ | |
* https://github.com/dkk/WrappingHStack | |
*/ | |
struct Example12: View { | |
var body: some View { | |
HStack(spacing: 0) { | |
HStack {}.frame(width: 50, height: 30).background(Color.red) | |
HStack {}.frame(width: 100, height: 30).background(Color.green) | |
HStack {}.frame(width: 80, height: 30).background(Color.blue) | |
HStack {}.frame(width: 60, height: 30).background(Color.purple) | |
HStack {}.frame(width: 120, height: 30).background(Color.brown) | |
HStack {}.frame(width: 160, height: 30).background(Color.cyan) | |
HStack {}.frame(width: 30, height: 30).background(Color.indigo) | |
HStack {}.frame(width: 300, height: 30).background(Color.mint) | |
HStack {}.frame(width: 150, height: 30).background(Color.orange) | |
HStack {}.frame(width: 130, height: 30).background(Color.pink) | |
// HStack {}.frame(width: 40, height: 30).background(Color.teal) | |
} | |
.frame(width: 300, alignment: .leading) | |
.clipped() | |
.background(Color.gray) | |
} | |
} | |
struct Example13: View { | |
var body: some View { | |
VStack { | |
VStack {}.frame(width: 100, height: 100).overlay( | |
RoundedRectangle(cornerRadius: 50) | |
.stroke(Color.red, lineWidth: 4) | |
) | |
// can't really make dotted | |
VStack {}.frame(width: 100, height: 100).overlay( | |
RoundedRectangle(cornerRadius: 25) | |
.stroke(Color.green, style: StrokeStyle(lineWidth: 6, lineCap: .butt, lineJoin: .miter, miterLimit: 0, dash: [5, 10], dashPhase: 0)) | |
) | |
VStack {}.frame(width: 100, height: 100).overlay( | |
Rectangle() | |
.stroke(Color.blue, style: StrokeStyle(lineWidth: 2, dash: [5])) | |
) | |
} | |
} | |
} | |
struct Example14: View { | |
var body: some View { | |
VStack(alignment: .leading) { | |
HStack(alignment: .top, spacing: 0) { | |
HStack {} | |
.frame(width: 30, height: 200) | |
.background(Color.red) | |
HStack {} | |
.frame(width: 200, height: 30) | |
.background(Color.blue) | |
} | |
.frame(width: 100, height: 100, alignment: .topLeading) | |
.background(Color.gray) | |
Text("This text goes after the example, the content should overflow on top of this.") | |
} | |
} | |
} | |
struct Example15: View { | |
var body: some View { | |
ZStack(alignment: .topLeading) { | |
HStack {} | |
.frame(width: 50, height: 50) | |
.background(Color.red) | |
.offset(x: 0, y: 0) | |
HStack {} | |
.frame(width: 50, height: 50) | |
.background(Color.blue) | |
.offset(x: 25, y: 25) | |
} | |
.frame(width: 150, height: 150, alignment: .topLeading) | |
.background(Color.gray) | |
} | |
} | |
struct Example16: View { | |
var body: some View { | |
ZStack(alignment: .topLeading) { | |
ZStack { | |
HStack {} | |
.frame(width: 50, height: 50) | |
.background(Color.red) | |
.offset(x: 10, y: 10) | |
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) | |
ZStack { | |
HStack {} | |
.frame(width: 50, height: 50) | |
.background(Color.green) | |
.offset(x: -10, y: 10) | |
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing) | |
ZStack { | |
HStack {} | |
.frame(width: 50, height: 50) | |
.background(Color.blue) | |
.offset(x: -10, y: -10) | |
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing) | |
ZStack { | |
HStack {} | |
.frame(width: 50, height: 50) | |
.background(Color.purple) | |
.offset(x: 10, y: -10) | |
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading) | |
} | |
.frame(width: 150, height: 150, alignment: .topLeading) | |
.background(Color.gray) | |
} | |
} | |
struct SizePreferenceKey: PreferenceKey { | |
static var defaultValue: CGSize = .zero | |
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {} | |
} | |
struct Example25: View { | |
private let totalFlexFactor = 3 | |
@State private var freeSpace: CGSize? = nil | |
func getFlexibleWidth(parentWidth: CGFloat, factor: Int) -> CGFloat { | |
return (CGFloat(factor) / CGFloat(totalFlexFactor)) * (freeSpace?.width ?? 0) | |
} | |
var body: some View { | |
GeometryReader { parentGeometry in | |
VStack { | |
Spacer() | |
HStack(spacing: 0) { | |
HStack() { Text("Width\n= 50").font(.system(size: 12)) } | |
.frame(maxWidth: 50, maxHeight: .infinity) | |
.background(Color.red) | |
HStack() { Text("Flex = 2").font(.system(size: 12)) } | |
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2), maxHeight: .infinity) | |
.background(Color.green) | |
HStack() { Text("Width\n= 80").font(.system(size: 12)) } | |
.frame(maxWidth: 80, maxHeight: .infinity) | |
.background(Color.blue) | |
HStack() { Text("Flex = 1").font(.system(size: 12)) } | |
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1), maxHeight: .infinity) | |
.background(Color.purple) | |
if (freeSpace == nil) { | |
HStack() {} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background( | |
GeometryReader { geometryProxy in | |
Color.clear | |
.preference(key: SizePreferenceKey.self, value: geometryProxy.size) | |
} | |
) | |
} | |
} | |
.frame(maxWidth: .infinity, maxHeight: 50) | |
.background(Color.gray) | |
.onPreferenceChange(SizePreferenceKey.self) { newSize in | |
if (freeSpace == nil) { | |
freeSpace = newSize | |
} | |
} | |
Spacer() | |
} | |
} | |
} | |
} | |
struct ContentView: View { | |
var body: some View { | |
Example4() | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
Example16() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment