SwiftUI 布局(Layout)基础

1、VStack(垂直布局)(对应还有LazyVStack懒加载垂直布局,iOS 14.0才可使用)

VStack 会一次性渲染所有视图,无论它们是在屏幕上还是屏幕外。 当您有少量子视图或不希望“懒加载”延迟渲染时,请使用常规 VStack。

import SwiftUI
struct ContentView: View {
    var body: some View {
        VStack(
            alignment: .leading,
            spacing: 10
        ) {
            ForEach(
                0...10,
                id: \.self
            ) {
                Text("Item \($0)")
                    .background(Color.blue)
            }
        }
    }}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

alignment:对接方式,左/中/右

extension HorizontalAlignment {

    /// A guide marking the leading edge of the view. 
    public static let leading: HorizontalAlignment

    /// A guide marking the horizontal center of the view.
    public static let center: HorizontalAlignment

    /// A guide marking the trailing edge of the view.
    public static let trailing: HorizontalAlignment
}

spacing:间距

截屏2021-12-26 23.32.42.png

2、HStack(水平布局)(对应还有LazyHStack懒加载水平布局,iOS 14.0才可使用)

HStack 会一次性渲染所有视图,无论它们是在屏幕上还是屏幕外。 当您有少量子视图或不希望“懒加载”延迟渲染时,请使用常规 HStack。

var body: some View {
    HStack(
        alignment: .top,
        spacing: 10
    ) {
        ForEach(
            1...5,
            id: \.self
        ) {
            Text("Item \($0)")
        }
    }
}
截屏2021-12-26 23.16.05.png
3、ZStack(层叠布局)

ZStack 为每个连续的子视图分配比前一个更高的 z 轴值,这意味着后面的子视图出现在前面的子视图的“顶部”。
下面的示例创建一个 100 x 100 点的 ZStack 矩形视图,填充六种颜色之一,将每个连续的子视图偏移 10 点,使它们不会完全重叠:

let colors: [Color] =
    [.red, .orange, .yellow, .green, .blue, .purple]

var body: some View {
    ZStack {
        ForEach(0..<colors.count) {
            Rectangle()
                .fill(colors[$0])
                .frame(width: 100, height: 100)
                .offset(x: CGFloat($0) * 10.0,
                        y: CGFloat($0) * 10.0)
        }
    }
}
截屏2021-12-26 23.19.59.png
import SwiftUI

struct ContentView: View {
   
    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.red)
                .frame(width:300, height:300)
                .zIndex(0)
            
            Rectangle()
                .fill(Color.blue)
                .frame(width:200, height:200)
            
            Rectangle()
                .fill(Color.yellow)
                .frame(width:100, height:100)
        }
    }
    
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
截屏2021-12-26 23.27.56.png

zIndex:层叠优先级,从大到小1-0

4、Spacer (填充布局)

一个灵活的填充空间布局,垂直/水平填充,默认填充满剩余所有空间,也可以指定填充的宽度或高度

  • 4-1 未填充前的水平布局


    截屏2021-12-27 23.26.59.png
  • 4-2 填充后的水平布局(垂直布局一样的效果)
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(
            alignment: .top,
            spacing: 10
        ) {
            Text("Item 1")
                .background(Color.purple)
            Spacer()
            Text("Item 2")
                .background(Color.purple)
            Spacer()
            Text("Item 3")
                .background(Color.purple)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
截屏2021-12-27 23.28.33.png
  • 4-3 填充后的水平布局(垂直布局一样的效果)
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(
            alignment: .top,
            spacing: 10
        ) {
            Spacer()
            Text("Item 1")
                .background(Color.purple)
            Spacer()
            Text("Item 2")
                .background(Color.purple)
            Spacer()
            Text("Item 3")
                .background(Color.purple)
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

截屏2021-12-27 23.28.45.png

minLength:设置填充最小宽度/高度

5、ScrollView

滚动视图在可滚动内容区域内显示其内容。 当用户执行适合平台的滚动手势时,滚动视图会调整底层内容的可见部分。 ScrollView 可以水平、垂直或同时滚动,但不提供缩放功能。(一般配合HStack、VStack等布局使用)
在以下示例中,ScrollView 允许用户滚动包含 100 个文本视图的 VStack。 列表后的图像显示了右侧滚动视图的临时可见滚动条; 您可以使用 ScrollView 初始值设定项的 showsIndicators 参数禁用它。

var body: some View {
    ScrollView {
        VStack(alignment: .leading) {
            ForEach(0..<100) {
                Text("Row \($0)")
            }
        }
    }
}
截屏2021-12-27 23.39.15.png

Axis.set: 设置滚动方向/水平/垂直
showsIndicators:是否显示滚动指示器

6、GeometryReader(相对布局)

一个容器视图,将其内容定义为它自己的大小和坐标空间的函数。可以获取到视图的大小和坐标

import SwiftUI

struct ContentView : View {
    var body: some View {
        
        VStack {
            
            Text("Hello There!").background(Color.orange)
            MyRectangle()
            
        }.frame(width: 150, height: 100).border(Color.yellow)

    }
}

struct MyRectangle: View {
    var body: some View {
        GeometryReader { geometry in
            Rectangle()
                .path(in: CGRect(x: geometry.size.width + 5,
                                 y: 0,
                                 width: geometry.size.width/2,
                                 height: geometry.size.height))
                .fill(Color.pink)
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
截屏2021-12-27 23.54.37.png
7、ViewBuilder

通常使用 ViewBuilder 作为子视图生成闭包参数的参数属性,允许这些闭包提供多个子视图。 例如,以下CustomView接受一个通过视图构建器生成一个或多个视图的闭包。(通常用来自定义View、dialog、toast等)

import SwiftUI

struct ContentView : View {
    var body: some View {
        CustomView{
            Text("Itme 1")
            Text("Itme 2")
            Text("Itme 3")
        }
    }
}

struct CustomView<Content>:View where Content:View {
    private let content:Content
    init(@ViewBuilder content:() -> Content) {
        self.content = content()
    }
    
    var body: some View{
        VStack{
            content
                .padding()
        }
        .foregroundColor(.orange)
        .background(Color.pink)
        .font(.title)
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
截屏2021-12-28 00.08.06.png
8、LazyVGrid (懒加载垂直网格布局)(iOS 14.0才可使用)

控件显示到屏幕里才会加载(性能会有提升)

import SwiftUI
struct ContentView : View {
    var body: some View {
        let columns: [GridItem] =
            Array(repeating: .init(.flexible(), spacing: 0), count: 4)
         ScrollView {
             LazyVGrid(columns: columns) {
                ForEach((0...79), id: \.self) {
                    let codepoint = $0 + 0x1f600
                    let emoji = String(Character(UnicodeScalar(codepoint)!))
                    Text("\(emoji)")
                        .font(.largeTitle)
                        .background(Color.blue)
                }
             }.font(.largeTitle)
         }
         .padding()
    }
}
截屏2021-12-28 21.46.41.png
9、LazyHGrid (懒加载水平网格布局)(iOS 14.0才可使用)

控件显示到屏幕里才会加载

import SwiftUI

struct ContentView : View {
    var body: some View {
        let rows: [GridItem] =
                Array(repeating: .init(.fixed(50)), count: 2)
        ScrollView(.horizontal) {
            LazyHGrid(rows: rows, alignment: .top) {
                ForEach((0...79), id: \.self) {
                    let codepoint = $0 + 0x1f600
                    let emoji = String(Character(UnicodeScalar(codepoint)!))
                    Text("\(emoji)")
                        .font(.largeTitle)
                        .background(Color.blue)
                }
            }
        }
        .padding()
    }
}
截屏2021-12-28 21.45.07.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容