You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
publicprotocolLayout:Animatable{staticvarlayoutProperties:LayoutProperties{get}associatedtypeCache=VoidtypealiasSubviews=LayoutSubviewsfunc updateCache(_ cache:inoutSelf.Cache, subviews:Self.Subviews)func spacing(subviews:Self.Subviews, cache:inoutSelf.Cache)->ViewSpacing/// We return our view size here, use the passed parameters for computing the/// layout.func sizeThatFits(
proposal:ProposedViewSize,
subviews:Self.Subviews,
cache:inoutSelf.Cache// 👈🏻 use this for calculated data shared among Layout methods)->CGSize/// Use this to tell your subviews where to appear.func placeSubviews(
in bounds:CGRect,// 👈🏻 region where we need to place our subviews into, origin might not be .zero
proposal:ProposedViewSize,
subviews:Self.Subviews,
cache:inoutSelf.Cache)// ... there are more a couple more optional methods}
下面例子是一个自定义的水平 stack 视图,为其所有子视图提供其最大子视图的宽度:
structMyEqualWidthHStack:Layout{/// Returns a size that the layout container needs to arrange its subviews./// - Tag: sizeThatFitsHorizontalfunc sizeThatFits(
proposal:ProposedViewSize,
subviews:Subviews,
cache:inoutVoid)->CGSize{
guard !subviews.isEmpty else{return.zero }letmaxSize=maxSize(subviews: subviews)letspacing=spacing(subviews: subviews)lettotalSpacing= spacing.reduce(0){ $0 + $1 }returnCGSize(
width: maxSize.width * CGFloat(subviews.count)+ totalSpacing,
height: maxSize.height)}/// Places the stack's subviews./// - Tag: placeSubviewsHorizontalfunc placeSubviews(
in bounds:CGRect,
proposal:ProposedViewSize,
subviews:Subviews,
cache:inoutVoid){
guard !subviews.isEmpty else{return}letmaxSize=maxSize(subviews: subviews)letspacing=spacing(subviews: subviews)letplacementProposal=ProposedViewSize(width: maxSize.width, height: maxSize.height)varnextX= bounds.minX + maxSize.width /2
for index in subviews.indices {subviews[index].place(
at:CGPoint(x: nextX, y: bounds.midY),
anchor:.center,
proposal: placementProposal)
nextX += maxSize.width + spacing[index]}}/// Finds the largest ideal size of the subviews.privatefunc maxSize(subviews:Subviews)->CGSize{letsubviewSizes= subviews.map{ $0.sizeThatFits(.unspecified)}letmaxSize:CGSize= subviewSizes.reduce(.zero){ currentMax, subviewSize inCGSize(
width:max(currentMax.width, subviewSize.width),
height:max(currentMax.height, subviewSize.height))}return maxSize
}/// Gets an array of preferred spacing sizes between subviews in the/// horizontal dimension.privatefunc spacing(subviews:Subviews)->[CGFloat]{
subviews.indices.map{ index in
guard index < subviews.count -1else{return0}returnsubviews[index].spacing.distance(
to:subviews[index +1].spacing,
along:.horizontal)}}}
session Compose custom layouts with SwiftUI
提供了新的 Grid 视图来同时满足 VStack 和 HStack。还有一个更低级别 Layout 接口,可以完全控制构建应用所需的布局。另外还有 ViewThatFits 可以自动选择填充可用空间的方式。
Grid 示例代码如下:
gridCellColumns()
modifier 可以让一个单元格跨多列。ViewThatFits 的新视图,允许根据适合的大小放视图。ViewThatFits 会自动选择对于当前屏幕大小合适的子视图进行显示。Ryan Lintott 的示例效果 ,对应示例代码 LayoutThatFits.swift 。
新的 Layout 协议可以观看 Swift Talk 第 308 期 The Layout Protocol 。
通过符合 Layout 协议,我们可以自定义一个自定义的布局容器,直接参与 SwiftUI 的布局过程。新的 ProposedViewSize 结构,它是容器视图提供的大小。
Layout.Subviews
是布局视图的子视图代理集合,我们可以在其中为每个子视图请求各种布局属性。下面例子是一个自定义的水平 stack 视图,为其所有子视图提供其最大子视图的宽度:
自定义 layout 只能访问子视图代理
Layout.Subviews
,而不是视图或数据模型。我们可以通过 LayoutValueKey 在每个子视图上存储自定义值,通过layoutValue(key:value:)
modifier 设置。然后,我们就可以通过 Layout 方法中的
Layout.Subviews
代理读取自定义LayoutValueKey
值:要在布局之间变化使用动画,需要用 AnyLayout,代码示例如下:
同时 Text 和图片也支持了样式布局变化,代码示例如下:
The text was updated successfully, but these errors were encountered: