本文将通过多个示例,介绍SwiftUI中几种常见的自定义方式,包括样式(Style)、视图修改器(ViewModifier)、自定义视图(Custom View)与视图扩展(View Extension ViewModifier是SwiftUI中一种非常强大的机制,允许我们将某些视图样式、行为封装成可复用的模块。 通过组合使用多个ViewModifier,我们可以实现复杂且整洁的界面设计。 案例 import SwiftUI struct CustomViewModifier: ViewModifier { let color: Color let cornerRadius : CGFloat // 在body中实现自定义ViewModifier func body(content: Content) -> some View { content
没有 Modifier 的视图是不完整的 SwiftUI 通过视图修饰符( ViewModifier )为视图的声明提供了巨大的灵活性。在本文的最后一部分,我们将对 Modifier 做一点探讨。 考虑到 View 协议所能提供的 API 有限,无法应对 modifier 的各种需求,SwiftUI 通过 ViewModifier 协议( _ViewModifier_Content )为 modifier 首先,我们先仿制一个 ViewModifier 协议: public protocol ViewModifier { associatedtype Body: View typealias / _ViewModifier_Content 提供了额外的 API ,在此就不进行复现了。 public struct _ViewModifier_Content<Modifier>: View where Modifier: ViewModifier { public typealias
public let label: ButtonStyleConfiguration.Label public let isPressed: Bool}ButtonStyle 协议的使用方式与 ViewModifier 同 ViewModifier 一样,可以通过环境值获取更多信息:struct RoundedAndShadowProButtonStyle:ButtonStyle { @Environment(\ HStack { Button("11"){print("1")} Button("22"){print("2")} }}.buttonStyle(.plain)注意事项同 ViewModifier
modifier(RotationEffectWithFrameModifier(angle: angle)) } } struct RotationEffectWithFrameModifier: ViewModifier 用 viewModifier 包装布局容器 在 SwiftUI 中,通常需要对布局容器进行二次包装后再使用。 这种开发者只提供一个子视图同时又需要对齐的布局容器,我们需要通过在 modifier 中添加一个 Color.clear 视图来解决对齐对象不足的问题 private struct MyFrameLayout: Layout, ViewModifier private struct MyFixedSizeLayout: Layout, ViewModifier { let horizontal: Bool let vertical: Bool
如果想实现严格意义上的轻扫可以采用如下的实现方法: •改成示例 2 的方式,用 ViewModifier 来包装 DragGesture•用 State 记录滑动时间•在 onEnded 中,只有满足速度 2.3 实现 public struct PressGestureViewModifier: ViewModifier { @GestureState private var startTimestamp 3.3 实现 public struct TapWithLocation: ViewModifier { @State private var locations: CGPoint?
ScrollStatusByIntrospectModifier(isScrolling: isScrolling)) }}struct ScrollStatusByIntrospectModifier: ViewModifier self.isScrolling = false } }) }}struct ScrollStatusMonitorExclusionModifier: ViewModifier nextValue: () -> CGRect) { value = nextValue() }}struct ScrollStatusMonitorCommonModifier: ViewModifier
import SwiftUI struct ScrollViewOffsetModifier: ViewModifier { //定义顶部锚点 var anchorPoint: Anchor
用自定义 Modifier 优雅管理焦点 (Simplifying Focus Management in SwiftUI with a Custom ViewModifier)[20] SwiftUI 2084&utm_medium=web [20] 用自定义 Modifier 优雅管理焦点 (Simplifying Focus Management in SwiftUI with a Custom ViewModifier
通过遵循 Animatable 协议,可以让 View 或 ViewModifier 具备获得动画数据的能力( AnimatableModifier 已被弃用)。 struct MyTransition: ViewModifier { // 自定义转场的包装对象要求符合 ViewModifier 协议 let rotation: Angle func 2022-05-04_19.55.51.2022-05-04 19_56_55 虽然 MyTransition 表面上并不符合 Animatable 协议,但其中的 rotationEffect (可动画 ViewModifier 另外,我们也可以使用符合 Animatable 的 GeometryEffect( 符合 ViewModifier 和 Animatable )来创建复杂的转场效果。
) -> some View { modifier(GetWidthModifier(width: width)) } } struct GetWidthModifier: ViewModifier modifier(MyVisualEffect(effect: effect)) } } public struct MyVisualEffect<Output: View>: ViewModifier effect(AnyView(content), proxy) } } } } struct GeometryProxyWrapper: ViewModifier
value: value, priority: priority, action: action)) }}@available(iOS 13,*)struct _MyTaskModifier: ViewModifier cancel() } }}@available(iOS 13,*)struct _MyTaskValueModifier<Value>: ViewModifier where
: value, priority: priority, action: action)) } } @available(iOS 13,*) struct _MyTaskModifier: ViewModifier cancel() } } } @available(iOS 13,*) struct _MyTaskValueModifier<Value>: ViewModifier
GeometryEffect是一个符合Animatable 和 ViewModifier 的协议。 AnimatableModifier 是一个 ViewModifier,符合 Animatable 协议,如果对这个协议不了解可以阅读之前发布的两篇文章。
另外也可以将常用的View修饰通过ViewModifier进行包装。ViewModifier可以维持自己的@State,可以自行管理状态。
{ static var previews: some View { ContentView() } } struct CornerModifier: ViewModifier
AnimatableModifier 是一个 ViewModifier,符合 Animatable 协议,如果对这个协议不了解可以阅读之前发布的两篇文章。
仅能在同一层次放置有限数量的视图) 为什么要谨慎使用 AnyView 如何避免使用 AnyView 为什么无论显示与否,视图都会包含所有选择分支的类型信息 为什么绝大多数的官方视图类型的 body 都是 Never ViewModifier AttributedString("World") } 添加 modifier 在继续完善构建器其他的方法之前,我们先为 AttributedStringBuilder 添加一些类似 SwiftUI 的 ViewModifier
在动画不复杂的情况下,可以通过创建一个符合 Animatable 协议的 ViewModifier 来同步观察动画的进程。详情请参阅 推文[17]、代码[18] 。 A:你可以通过创建自定义 ViewModifier 来封装其中的一些代码。
与大多数的 View Extension 和 ViewModifier 不同,在视图中,通过 .sheet 或 .fullScreenCover来声明的模态视图内容代码的闭包,只会在显示模态视图的时候才会被调用
GeometryEffect GeometryEffect是一个符合Animatable和ViewModifier的协议。