4.布局系统

大家好,我是K哥。一名独立开发者,同时也是Swift开发框架【Aquarius 】的作者,悦记爱寻车app的开发者。

Aquarius开发框架旨在帮助独立开发者和中小型团队,完成iOS App的快速实现与迭代。使用框架开发将给你带来简单、高效、易维护的编程体验。


Aquarius布局系统简介

Aquarius开发框架 提供了一套完整的、极简的布局系统。通过该布局系统,你可以轻松的完成基于代码控制的视图布局。

核心价值

  • 🎯 一行顶多行 - 极简API,大幅减少代码量
  • 动效零成本 - 所有布局变化天然支持动画
  • 🔗 关系式布局 - 直观表达视图间相对关系
  • 📦 批量好帮手 - 一次性操作多个视图
  • 🔄 无缝兼容 - 基于原生frame,即插即用

系统特点

  • 直观的定位和大小调整方法
  • 内置动画支持
  • 多视图批量操作

参见源码

  • UIView+aLayout.swift
  • Array+aLayout.swift

复杂度:

  • 基础布局:提供了对控件的基础设置
  • 高级布局:提供了控件间关系型的动态设置

基础布局:重塑单个视图的操控体验

处理单个视图

位置

使用框架提供的方法,你可以轻松的完成视图位置的获取和设置。

  • 获取x位置

不使用框架的获取方式

swift 复制代码
let x: CGFloat = myView.frame.origin.x

使用框架的获取方式

swift 复制代码
let x: CGFloat = myView.x()
//或
let x: CGFloat = myView.left()
  • 设置x位置

不使用框架的获取方式

swift 复制代码
myView.frame.origin.x = 10.0

使用框架的获取方式

swift 复制代码
myView.x(x: 10.0)
//或
myView.left(left: 10.0)
  • 获取y位置

不使用框架的获取方式

swift 复制代码
let y: CGFloat = myView.frame.origin.y

使用框架的获取方式

swift 复制代码
let y: CGFloat = myView.y()
//或
let y: CGFloat = myView.top()
  • 设置y位置

不使用框架的获取方式

swift 复制代码
myView.frame.origin.y = 10.0

使用框架的获取方式

swift 复制代码
myView.y(y: 10.0)
//或
myView.top(top: 10.0)
  • 获取右侧位置

不使用框架的获取方式

swift 复制代码
let right: CGFloat = myView.frame.origin.x + myView.frame.size.width

使用框架的获取方式

swift 复制代码
let right: CGFloat = myView.right()
  • 设置右侧位置

不使用框架的获取方式

swift 复制代码
myView.frame.origin.x = 200.0 - myView.frame.size.width

使用框架的获取方式

swift 复制代码
myView.right(right: 200)
  • 获取底部位置

不使用框架的获取方式

swift 复制代码
let bottom: CGFloat = myView.frame.origin.y + myView.frame.size.height

使用框架的获取方式

swift 复制代码
let bottom: CGFloat = myView.bottom()
  • 设置底部位置

不使用框架的获取方式

swift 复制代码
myView.frame.origin.y = 200.0 - myView.frame.size.height

使用框架的获取方式

swift 复制代码
myView.bottom(bottom: 200.0)

大小

使用框架提供的方法,你可以轻松的完成视图大小的获取和设置。

  • 获取宽度

不使用框架的获取方式

swift 复制代码
let width: CGFloat = myView.frame.size.width

使用框架的获取方式

swift 复制代码
let width: CGFloat = myView.width()
  • 设置宽度

不使用框架的获取方式

swift 复制代码
myView.frame.size.width = 100.0

使用框架的获取方式

swift 复制代码
myView.width(width: 100.0)
  • 获取高度

不使用框架的获取方式

swift 复制代码
let height: CGFloat = myView.frame.size.height

使用框架的获取方式

swift 复制代码
let height: CGFloat = myView.height()
  • 设置高度

不使用框架的获取方式

swift 复制代码
myView.frame.size.height = 100.0

使用框架的获取方式

swift 复制代码
myView.height(height: 100.0)

point

  • 获取point

不使用框架的获取方式

swift 复制代码
let point: CGPoint = myView.frame.origin

使用框架的获取方式

swift 复制代码
let point: CGPoint = myView.point()
  • 设置point

不使用框架的获取方式

swift 复制代码
myView.frame.origin = CGPoint(x: 10.0, y: 10.0)

使用框架的获取方式

swift 复制代码
myView.point(x: 10.0, y: 10.0)
//或
myView.point(point: CGPoint(x: 10.0, y: 10.0)
//或
myView.point(points: [10.0, 10.0])
//当x, y值相同时
myView.point(xy: 10.0)

Size

  • 获取Size

不使用框架的获取方式

swift 复制代码
let size: CGSize = myView.frame.size

使用框架的获取方式

swift 复制代码
let size: CGSize = myView.size()
  • 设置Size

不使用框架的获取方式

swift 复制代码
myView.frame.size = CGSize(width: 100.0, height: 100.0)

使用框架的获取方式

swift 复制代码
myView.size(width: 100.0, height: 100.0)
//或
myView.size(w: 100.0, h: 100.0)
//或
myView.size(size: CGSize(width: 100.0, height: 100.0))
//或
myView.size(sizes: [100.0, 100.0])
//当宽和高相同时
myView.size(widthHeight: 100.0)

frame

  • 获取frame

不使用框架的获取方式

swift 复制代码
let frame: CGRect = myView.frame

使用框架的获取方式

swift 复制代码
let frame: CGRect = myView.frame()
  • 设置frame

不使用框架的获取方式

swift 复制代码
myView.frame = CGRect(x: 10.0, y: 10.0, width: 100.0, height: 100.0)
//或
myView.frame = CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: CGSize(width: 100.0, height: 100.0))

使用框架的获取方式

swift 复制代码
myView.frame(frame: CGRect(x: 10.0, y: 10.0, width: 100.0, height: 100.0))
//或
myView.frame(x: 10.0, y: 10.0, w: 100.0, h: 100.0)
//或
myView.frame(frames: [10.0, 10.0, 100.0, 100.0])
//当x, y和宽、高相同时
myView.frame(xy: 10.0, widthHeight: 100.0)

处理多个视图

基础操作

  • 设置多个视图相同的x值

不使用框架的获取方式

swift 复制代码
view1.frame.origin.x = 10.0
view2.frame.origin.x = 10.0

使用框架的获取方式

swift 复制代码
UIView.x(x: 10.0, views: [view1, view2])
//或
UIView.left(left: 10.0, views: [view1, view2])
  • 设置多个视图相同的right值

使用框架的获取方式

swift 复制代码
UIView.right(right: 10.0, views: [view1, view2])
  • 设置多个视图相同的y值

不使用框架的获取方式

swift 复制代码
view1.frame.origin.y = 10.0
view2.frame.origin.y = 10.0

使用框架的获取方式

swift 复制代码
UIView.y(y: 10.0, views: [view1, view2])
//或
UIView.top(top: 10.0, views: [view1, view2])
  • 设置多个视图相同的bottom值

使用框架的获取方式

swift 复制代码
UIView.bottom(bottom: 10.0, views: [view1, view2])
  • 设置多个视图相同的宽度

不使用框架的获取方式

swift 复制代码
view1.frame.size.width = 100.0
view2.frame.size.width = 100.0

使用框架的获取方式

swift 复制代码
UIView.width(width: 100.0, views: [view1, view2])
  • 设置多个视图相同的高度

不使用框架的获取方式

swift 复制代码
view1.frame.size.height = 100.0
view2.frame.size.height = 100.0

使用框架的获取方式

swift 复制代码
UIView.height(height: 100.0, views: [view1, view2])
  • 设置多个视图相同的point

不使用框架的获取方式

swift 复制代码
view1.frame.origin = CGPoint(x: 10, y: 10)
view2.frame.origin = CGPoint(x: 10, y: 10)

使用框架的获取方式

swift 复制代码
UIView.point(x: 10.0, y: 10.0, views: [view1, view2])
//或
UIView.point(point: CGPoint(x: 10.0, y: 10.0), views: [view1, view2])
//或
UIView.point(points: [10.0, 10.0], views: [view1, view2])
//当x, y值相同时
UIView.point(xy: 10.0, views: [view1, view2])
  • 设置多个视图相同的Size

不使用框架的获取方式

swift 复制代码
view1.frame.size = CGSize(width: 100.0, height: 100.0)
view2.frame.size = CGSize(width: 100.0, height: 100.0)

使用框架的获取方式

swift 复制代码
UIView.size(width: 100.0, height: 100.0, views: [view1, view2])
//或
UIView.size(w: 100.0, h: 100.0, views: [view1, view2])
//或
UIView.size(size: CGSize(width: 100.0, height: 100.0), views: [view1, view2])
//或
UIView.size(sizes: [100.0, 100.0], views: [view1, view2])
//当宽和高相同时
UIView.size(widthHeight: 100.0, views: [view1, view2])
  • 设置多个视图相同的frame

不使用框架的获取方式

swift 复制代码
view1.frame = CGRect(x: 10.0, y: 10.0, width: 100.0, height: 100.0)
view2.frame = CGRect(x: 10.0, y: 10.0, width: 100.0, height: 100.0)
//或
view1.frame = CGRect(origin: CGPoint(x: 10.0, y: 10.0), size:CGSize(width: 100.0, height: 100.0))
view2.frame = CGRect(origin: CGPoint(x: 10.0, y: 10.0), size:CGSize(width: 100.0, height: 100.0))

使用框架的获取方式

swift 复制代码
UIView.frame(x: 10.0, y: 10.0, w: 100.0, h: 100.0, views: [view1, view2])
//或
UIView.frame(frame: CGRect(x: 10.0, y: 10.0, width: 100.0, height: 100.0), views: [view1, view2])
//或
UIView.frame(frame: CGRect(origin: CGPoint(x: 10.0, y: 10.0), size: CGSize(width: 100.0, height: 100.0)), views: [view1, view2])
//或
UIView.frame(frames: [10.0, 10.0, 100.0, 100.0], views: [view1, view2])
//当x, y和宽, 高相等时
UIView.frame(xy: 10.0, widthHeight: 100.0, views: [view1, view2])

对齐操作

框架支持多个视图的对齐

swift 复制代码
//顶端对齐
UIView.top(views: [view1, view2, view3])
//底部对齐
UIView.bottom(views: [view1, view2, view3])
//左侧对齐
UIView.left(views: [view1, view2, view3])
//右侧对齐
UIView.right(views: [view1, view2, view3])

支持对齐到某个目标位置

swift 复制代码
//顶端对齐
UIView.top(views: [view1, view2, view3], position: 50)
//底部对齐
UIView.bottom(views: [view1, view2, view3], position: 50)
//左侧对齐
UIView.left(views: [view1, view2, view3], position: 50)
//右侧对齐
UIView.right(views: [view1, view2, view3], position: 50)

分布操作

均匀分布视图:

swift 复制代码
// 在第一个和最后一个视图之间水平分布视图
UIView.horizontal(views: [view1, view2, view3, view4]) 

// 在第一个和最后一个视图之间垂直分布视图
UIView.vertical(views: [view1, view2, view3, view4])

组合对齐和分布操作

在一次操作中对齐和分布视图:

swift 复制代码
// 顶端对齐并且水平分布视图
UIView.topAndHorizontal(views: [view1, view2, view3, view4]) 
// 顶端对齐到某个目标位置并且水平分布视图
UIView.topAndHorizontal(views: [view1, view2, view3, view4], position: 50) 
// 底部对齐并且水平分布视图
UIView.bottomAndHorizontal(views: [view1, view2, view3, view4]) 
// 底部对齐到某个目标位置并且水平分布视图
UIView.bottomAndHorizontal(views: [view1, view2, view3, view4], position: 50) 

// 左侧对齐并且垂直分布视图
UIView.leftVertical(views: [view1, view2, view3, view4])
// 左侧对齐到某个目标位置并且垂直分布视图
UIView.leftVertical(views: [view1, view2, view3, view4], position: 50)
// 右侧对齐并且垂直分布视图
UIView.rightVertical(views: [view1, view2, view3, view4])
// 右侧对齐到某个目标位置并且垂直分布视图
UIView.rightVertical(views: [view1, view2, view3, view4], position: 50)

批量操作

框架支持数组的方式批量操作视图

swift 复制代码
let views: [UIView] = [view1, view2, view3]

views.width(width: 100.0)
views.width(width: 100.0, 1)//设置数组中第2个UIView的宽度

views.height(height: 100.0)
views.height(height: 100.0, 1)//设置数组中第2个UIView的高度

高级布局:构建智能的、响应式的界面

Aquarius开发框架提供了一个强大且灵活的布局系统,超越了基本的定位功能。通过高级布局技术,帮助你用最少的代码和最大的灵活性创建复杂的UI布局。

Aquarius开发框架 通过全面的布局方法扩展了UIView,这些方法建立在原生基于框架的布局系统之上,使其更加直观和强大。与Auto Layout的基于约束的方法不同,Aquarius开发框架提供了直接、命令式的API,易于理解且可以无缝动画。

相对定位

基础操作

Aquarius开发框架最强大的功能之一是它能够将视图相对于彼此定位。这消除了在排列视图时进行复杂计算的需要。

swift 复制代码
// 将viewB定位在viewA下方,间距为10pt
viewB.alignTop(view: viewA, offset: 10)

// 将viewB定位在viewA右侧,间距为15pt
viewB.alignLeft(view: viewA, offset: 15)

// 将viewB定位在viewA左侧,间距为8pt
viewB.alignRight(view: viewA, offset: 8)

// 将viewB定位在viewA上方,间距为12pt
viewB.alignBottom(view: viewA, offset: 12)

批量操作

swift 复制代码
let views: [UIView] = [view1, view2, view3]

// 将views数组定位在viewA下方,间距为8pt
views.alignTop(view: viewA, offset: 8)

// 将views数组中第2个视图定位在viewA下方,间距为8pt
views.alignTop(view: viewA, offset: 8, 1)

// 将views数组定位在viewA上方,间距为8pt
views.alignBottom(view: viewA, offset: 8)

// 将views数组中第2个UI视图在viewA上方,间距为8pt
views.alignBottom(view: viewA, offset: 8, 1)

// 将views数组定位在viewA右侧,间距为8pt
views.alignLeft(view: viewA, offset: 8)

// 将views数组中第2个视图视图iewA右侧,间距为8pt
views.alignLeft(view: viewA, offset: 8, 1)

// 将views数组定位在viewA左侧,间距为8pt
views.alignRight(view: viewA, offset: 8)

// 将views数组中第2个UI视图视图wA左侧,间距为8pt
views.alignRight(view: viewA, offset: 8, 1)

这些方法简化了流布局的创建,并能够在处理动态内容时无需手动计算位置。

等同定位

基础操作

当希望视图共享相同的边缘位置时,equal方法提供了一个简洁的语法

swift 复制代码
// 使viewB的左边缘与viewA相同(可选偏移)
viewB.equalLeft(target: viewA, offset: 5)

// 使viewB的右边缘与viewA相同
viewB.equalRight(target: viewA)

// 使viewB的顶部边缘与viewA相同
viewB.equalTop(target: viewA)

// 使viewB的底部边缘与viewA相同
viewB.equalBottom(target: viewA)

// 使viewB的大小与viewA相同
viewB.equalSize(target: viewA)

// 使viewB的框架与viewA相同
viewB.equalRect(target: viewA)

// 使viewB的左侧边缘设置为0
viewB.equalZeroLeft()

// 使viewB的顶端边缘设置为0
viewB.equalZeroTop()

// 使viewB的左侧边缘和顶端边缘设置为0
viewB.equalZeroTopAndLeft()

批量操作

swift 复制代码
let views: [UIView] = [view1, view2, view3]

// 使views数组的左边缘与viewA相同,间距为5pt
views.equalLeft(target: viewA, offset: 5)

// 使views数组中第2个视图的左边缘与viewA相同,间距为5pt
views.equalLeft(target: viewA, offset: 5, 1)

// 使views数组的右边缘与viewA相同,间距为5pt
views.equalRight(target: viewA, offset: 5)

// 使views数组中第2个UI视图边缘与viewA相同,间距为5pt
views.equalRight(target: viewA, offset: 5, 1)

// 使views数组的宽度与viewA相同,间距为5pt
views.equalWidth(target: viewA, offset: 5)

// 使views数组中第2个视图视图viewA相同,间距为5pt
views.equalWidth(target: viewA, offset: 5, 1)

// 使views数组的高度与viewA相同,间距为5pt
views.equalHeight(target: viewA, offset: 5)

// 使views数组中第2个UI视图视图ewA相同,间距为5pt
views.equalHeight(target: viewA, offset: 5, 1)

这种方法非常适合创建对齐的UI元素,并在界面中保持视觉和谐。

屏幕感知定位

Aquarius开发框架提供了方便的方法来处理屏幕尺寸和系统UI元素:

swift 复制代码
// 设置视图宽度与屏幕宽度相同
view.equalScreenWidth()

// 设置视图高度与屏幕高度相同
view.equalScreenHeight()

// 设置视图宽度和高度与屏幕高度相同
view.equalScrenSize()

// 设置视图高度与屏幕高度相同,减去状态栏高度
view.equalScreenHeightNoStatus()

// 设置视图高度与屏幕高度相同,减去导航栏高度
view.screenHeightNoNavigation()

// 设置视图高度与屏幕高度相同,减去状态栏和导航栏高度
view.screenHeightNoStatusNoNavigation()

// 设置视图高度与屏幕高度相同,减去底部安全区高度
view.screenHeightNoSafeAreaFooter()

// 设置视图高度与屏幕高度相同,减去tabBar高度
view.screenHeightNoTabBar()

// 设置视图高度与屏幕高度相同,减去状态栏和底部安全区高度
view.screenHeightNoStatusNoSafeAreaFooter()

// 设置视图高度与屏幕高度相同,减去状态栏和tabBar高度
view.screenHeightNoStatusNoTabBar()

// 设置视图高度与屏幕高度相同,减去状态栏、底部安全区和tabBar高度
view.screenHeightNoStatusNoSafeAreaFooterNoTabBar()

// 设置视图高度与屏幕高度相同,减去导航栏和底部安全区高度
view.screenHeightNoNavigationNoSafeAreaFooter()

// 设置视图高度与屏幕高度相同,减去导航栏和tabBar高度
view.screenHeightNoNavigationNoTabBar()

// 设置视图高度与屏幕高度相同,减去导航栏、底部安全区和tabBar高度
view.screenHeightNoNavigationNoSafeAreaFooterNoTabBar()

// 设置视图高度与屏幕高度相同,减去状态栏、导航栏和底部安全区高度
view.screenHeightNoStatusNoNavigationNoSafeAreaFooter()

// 设置视图高度与屏幕高度相同,减去状态栏、导航栏和tabBar高度
view.screenHeightNoStatusNoNavigationNoTabBar()

// 设置视图高度与屏幕高度相同,减去状态栏、导航栏、底部安全区和tabBar高度
view.screenHeightNoStatusNoNavigationNoSafeAreaFooterNoTabBar()

动画集成:让界面"活"起来

Aquarius开发框架 针对布局系统 提供简单的动画,所有布局系统相关的方法均提供动画功能

swift 复制代码
// 在0.3秒内动画改变宽度
view.width(width: 200, animate: true, duration: 0.3)

// 使用默认动画时长改变位置
view.left(left: 50, animate: true)

// 使用自定义时序动画多个视图到相同位置
UIView.bottom(bottom: 500, animate: true, duration: 0.5, views: [view1, view2, view3])
...

这种内置的动画支持使创建布局状态之间的平滑过渡变得简单,而无需额外代码。

实战案例:悦记 NoteView 布局剖析

下面以悦记APPNoteViewa_Layout 方法为例,展示Aquarius开发框架布局系统的具体使用案例:

swift 复制代码
import UIKit
import Foundation

import Aquarius
import CommonFramework

class NoteView: BaseView {
    ...
    override func a_Layout() {
        super.a_Layout()

        searchBar.frame(frames: [
                8,
                8,
                screenWidth()-8*2,
                52
            ])

        noteTableView.size(sizes: [
                screenWidth(),
                screenHeight()-navigationBarHeight()-safeAreaFooterHeight()-tabBarHeight()-8
            ])
        noteTableView.equalTop(target: searchBar)
        noteTableView.equalLeft(target: self)

        footerView.equalWidth(target: noteTableView)
        footerView.height(height: 48.0)

        activityIndicatorView.equalSize(target: footerView)
        activityIndicatorView.equalZeroTopAndLeft()

        leftSpaceView.width(width: NoteCell.distance)
        leftSpaceView.equalHeight(target: noteTableView)
        leftSpaceView.equalZeroLeft()
        leftSpaceView.equalTop(target: noteTableView)
        leftSpaceView.target(rightSpaceView)
        leftSpaceView.equals([.size, .top])

        rightSpaceView.left(left: screenWidth()-NoteCell.distance)

        createNoteButton.size(widthHeight: 60)
        createNoteButton.point(points: [
                screenWidth()-60-16,
                screenHeight()-statusBarHeight()-navigationBarHeight()-tabBarHeight()-safeAreaFooterHeight()-createNoteButton.height()
            ])
    }
    ...
}

代码解读

  • 关系清晰 :视图间的依赖关系(如 equalTop, equalWidth)让布局逻辑一目了然。
  • 易于维护:当某个视图的尺寸或位置需要调整时,只需修改一处,相关视图会自动更新。
  • 动态适应 :使用 screenHeight(), navigationBarHeight() 等方法,布局能自动适应不同的设备尺寸和系统状态。

为什么选择Aquarius布局系统

特性 Aquarius 原生Frame AutoLayout
代码简洁性 🏆 极致简洁 重复繁琐 冗长复杂
学习成本 🏆 几分钟上手 较低 曲线陡峭
动画支持 🏆 原生内置 需手动实现 实现复杂
运行性能 🏆 原生级性能 最佳 布局计算开销

适用场景

  • 🎯 独立开发者:追求开发效率,希望快速迭代。
  • 🎯 动态UI:界面元素需要频繁变化、动画丰富的应用。
  • 🎯 代码控:喜欢用代码精确控制每一个像素,厌恶Storyboard的臃肿。
  • 🎯 迁移项目:老项目基于Frame,希望用最小成本引入现代布局方式。

总结

Aquarius开发框架的布局系统提供了Auto Layout的强大替代方案,强调可读性、简洁性和动画集成。通过本篇文章介绍的相关技术,你可以用更少的代码创建复杂的布局,同时保持对UI元素定位和动画的完全控制。

直观的相对定位、灵活的分布方法和内置的动画支持相结合,使Aquarius开发框架成为需要创建动态、响应式界面的开发者的绝佳选择,而无需约束布局的复杂性。


立即体验Aquarius:

第一步:探索资源

第二步:体验效果

  • 📱 下载示例APP悦记 | 爱寻车 - 感受真实项目中的流畅体验

第三步:沟通交流

相关推荐
HarderCoder7 小时前
Swift 函数完全指南(四):从 `@escaping` 到 `async/await`——打通“回调→异步→并发”任督二脉
swift
HarderCoder8 小时前
Swift 函数完全指南(三):`@autoclosure`、`rethrows`、`@escaping` 与内存管理
swift
HarderCoder8 小时前
Swift 函数完全指南(二):泛型函数与可变参数、函数重载、递归、以及函数式编程思想
swift
HarderCoder8 小时前
Swift 函数完全指南(一)——从入门到嵌套
swift
jh_cao18 小时前
(4)SwiftUI 基础(第四篇)
ios·swiftui·swift
progalchemist1 天前
Quick SwiftObjective-C测试框架入门教程
开发语言·其他·objective-c·swift
HarderCoder1 天前
Swift 闭包(Closure)从入门到深入:语法、捕获与实战
swift
HarderCoder2 天前
Swift 集合类型详解(三):自定义集合、持久化结构与 ORM 共舞
swift
HarderCoder2 天前
Swift 集合类型详解(一):Array、Set、Dictionary 全貌与选型思路
swift