diff --git a/Demo/Shared/Demos/CustomMenuDemo.swift b/Demo/Shared/Demos/CustomMenuDemo.swift index 81b9617..44d66ca 100644 --- a/Demo/Shared/Demos/CustomMenuDemo.swift +++ b/Demo/Shared/Demos/CustomMenuDemo.swift @@ -67,6 +67,7 @@ struct CustomMenuDemo: View { } .frame(maxHeight: 300) #if targetEnvironment(macCatalyst) || !os(macOS) + // In macOS, the container view displayed abnormally when positioned to the toolbar via matchedGeometryEffect. .toolbar { // Button2 Button { @@ -80,7 +81,7 @@ struct CustomMenuDemo: View { isPresented: $showButton2, content: MenuView( isPresented: $showButton2, - transitionType: 1, + transitionType: transitionType, namespace: menu, id: button2, anchor: .topTrailing @@ -147,9 +148,11 @@ struct MenuView: View { } struct MenuContainerConfiguration: ContainerConfigurationProtocol { - var displayType: ContainerViewDisplayType = .stacking - var queueType: ContainerViewQueueType = .oneByOne - var alignment: Alignment? = .top + let displayType: ContainerViewDisplayType = .stacking + let queueType: ContainerViewQueueType = .oneByOne + let alignment: Alignment? = .top + // Set to true to prevent the menu (for button2) in the toolbar from displaying abnormally when the transition is scale + let clipped = true var shadowStyle: ContainerViewShadowStyle? { .radius(10) diff --git a/Demo/Shared/en.lproj/Localizable.strings b/Demo/Shared/en.lproj/Localizable.strings index 75fb65e..2688976 100644 --- a/Demo/Shared/en.lproj/Localizable.strings +++ b/Demo/Shared/en.lproj/Localizable.strings @@ -91,5 +91,5 @@ "Transition1" = "Scale"; "Transition2" = "Opacity"; "PopMenu" = "Pop Menu"; -"CustomMenuDescription" = "By using Namespace + ID, the position of the container view can be accurately positioned, and the custom menu can be realized with the correct transition, anchor point and other information. This logic also applies to scenarios such as beginner's guides, tips, etc."; +"CustomMenuDescription" = "By using Namespace + ID, the position of the container view can be accurately positioned, and the custom menu can be realized with the correct transition, anchor point and other information. This logic also applies to scenarios such as beginner's guides, tips, etc.\n\n**Note**: Positioning the container view via matchedGeometryEffect will cause some transitions that generate displacement to fail (eg: slide, move, offset)"; "Item %lld" = "Item %lld"; diff --git a/Demo/Shared/zh-Hans.lproj/Localizable.strings b/Demo/Shared/zh-Hans.lproj/Localizable.strings index 16bab64..f2b5abb 100644 --- a/Demo/Shared/zh-Hans.lproj/Localizable.strings +++ b/Demo/Shared/zh-Hans.lproj/Localizable.strings @@ -91,5 +91,5 @@ "Transition1" = "缩放"; "Transition2" = "透明度"; "PopMenu" = "弹出菜单"; -"CustomMenuDescription" = "通过利用 Namespace + ID 可以精确定位容器视图的位置,配合正确的转场、锚点等信息,实现自定义菜单。此逻辑同样适用于例如新手指南、tips 等场景。"; +"CustomMenuDescription" = "通过利用 Namespace + ID 可以精确定位容器视图的位置,配合正确的转场、锚点等信息,实现自定义菜单。此逻辑同样适用于例如新手指南、tips 等场景。\n\n**注意**:通过 matchedGeometryEffect 定位容器视图,将会导致部分产生位移的转场失效(例如:slide、move、offset)。"; "Item %lld" = "项目 %lld"; diff --git a/README.md b/README.md index dc68678..f69189d 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ In SwiftUI, describing views has become very easy, so we can completely extract * Multiple container support * Supports multiple views within a single container * Push views to any specified container within or outside of SwiftUI view code -* The configuration of the container can be modified dynamically (except for the queue type) +* The configuration of the container can be modified dynamically (except for `queue type` and `clipped`) * Views inside a container can be arranged in multiple ways * There are multiple queue types to guide the container on how to display the view @@ -190,7 +190,11 @@ Other properties: * insets - In stacking mode, the value is an insets value of the view. In horizontal and vertical mode, the value is an insets value of the view group. + In stacking mode, the value is an insets value of the view. In horizontal and vertical mode, the value is an insets value of the view group + +* clipped + + Clip the container, set to true when you want to limit the bounds of the view transition * Configuration for all other container views (used as defaults for container views) diff --git a/READMECN.md b/READMECN.md index 51fcfde..8cdbcf1 100644 --- a/READMECN.md +++ b/READMECN.md @@ -47,7 +47,7 @@ SwiftUI Overlay Container 是一个用于 SwiftUI 的视图容器组件。一个 * 支持多个容器 * 单一容器内支持多个视图 * 可在 SwiftUI 视图代码内或视图代码外向任意指定的容器推送视图 -* 可以动态修改容器的配置(除了队列类型) +* 可以动态修改容器的配置(除了 queue type 和 clipped) * 容器内的视图有多种排列方式 * 有多种队列类型以指导容器如何显示视图 @@ -187,6 +187,10 @@ struct MyContainerConfiguration:ContainerConfigurationProtocol{ 在 stacking 模式下,该值为视图的内嵌值。在 horizontal 和 vertical 模式下,该值为视图组的内嵌值。 +* clipped + + 对容器进行剪裁,当想限制视图转换的边界时需要设置为真 + * 其他所有容器视图的配置(用作容器视图的默认值) 详情参阅下方的配置容器视图 diff --git a/Sources/SwiftUIOverlayContainer/Container/Container.swift b/Sources/SwiftUIOverlayContainer/Container/Container.swift index 26a4eaa..e785782 100644 --- a/Sources/SwiftUIOverlayContainer/Container/Container.swift +++ b/Sources/SwiftUIOverlayContainer/Container/Container.swift @@ -100,7 +100,7 @@ struct OverlayContainer: View { } var body: some View { - Group { + GeometryReader { _ in switch configuration.displayType { case .stacking: GenericStack(displayType: configuration.displayType, alignment: .center) { @@ -188,11 +188,12 @@ struct OverlayContainer: View { queueHandler.maximumNumberOfViewsInMultiple = newMaximumNumberOfViewsInMultipleMode } // Prohibition of changing the containerName and the queueType - .onChange(of: configuration.queueType, containerName) { _ in + .onChange(of: configuration.queueType, containerName, configuration.clipped) { _ in #if DEBUG - fatalError("❌ Can't change container name or queue type in runtime, this message only show in Debug mode.") + fatalError("❌ Can't change container name,queue type and clipped in runtime, this message only show in Debug mode.") #endif } + .clipped(enable: configuration.clipped) } } diff --git a/Sources/SwiftUIOverlayContainer/Container/ContainerProtocols.swift b/Sources/SwiftUIOverlayContainer/Container/ContainerProtocols.swift index b9a9293..3f7801e 100644 --- a/Sources/SwiftUIOverlayContainer/Container/ContainerProtocols.swift +++ b/Sources/SwiftUIOverlayContainer/Container/ContainerProtocols.swift @@ -48,7 +48,7 @@ public extension ContainerTypeConfigurationProtocol { /// A type defines partial arrangement configuration of view in the container public protocol ContainerCompositionProtocol { - /// Spacing between each view when the display type is horizontal or vertical, and queue type is mulitple + /// Spacing between each view when the display type is horizontal or vertical, and queue type is multiple var spacing: CGFloat { get } /// Insets of view or view group in container /// @@ -56,12 +56,20 @@ public protocol ContainerCompositionProtocol { /// /// In vertical or horizontal mode, insets will be added to the view group (VStack or HStack) var insets: EdgeInsets { get } + + /// Clip the container to its bounding rectangle frame + /// + /// Pass true when the bounds of the view's transition need to limited + /// Can't be changed dynamically + var clipped: Bool { get } } public extension ContainerCompositionProtocol { var spacing: CGFloat { 10 } var insets: EdgeInsets { .init() } + + var clipped: Bool { false } } /// A combined protocol that defines all the configuration of the container diff --git a/Sources/SwiftUIOverlayContainer/Extensions/SwiftUI.swift b/Sources/SwiftUIOverlayContainer/Extensions/SwiftUI.swift index c795186..1c044ca 100644 --- a/Sources/SwiftUIOverlayContainer/Extensions/SwiftUI.swift +++ b/Sources/SwiftUIOverlayContainer/Extensions/SwiftUI.swift @@ -88,3 +88,15 @@ extension View { .onChange(of: value3, perform: { newValue3 in action((value1, value2, newValue3)) }) } } + +// condition clip +extension View { + @ViewBuilder + func clipped(enable: Bool) -> some View { + if enable { + clipped() + } else { + self + } + } +}