苹果是如何在这个模式中创建导航视图的?

发布于 2025-01-17 05:42:12 字数 3026 浏览 2 评论 0原文

在 iOS 设置 >音乐> Apple Music 和隐私,有一个模式我基本上已经成功复制了,除了两种方式(Apple 模式的简短演示是 此处)。首先,我不知道如何复制文本开头的要点。其次,我不知道如何隐藏导航栏标题,直到滚动经过徽标和模式标题。该行为与 .inline 导航标题样式匹配,并表明徽标和标题实际上是导航栏标题的一部分。

此处的答案实际上非常有帮助让导航栏显示出来。我还尝试使用 此处 将图像添加到工具栏,但这并没有给出所需的结果。我尝试添加填充,因为图像被压缩到导航栏中,但这不起作用。最后,我尝试在 .principal 位置中使用 VStack 在其下方添加图像和文本,但这也不起作用。

这是父视图中的代码:

struct ModalNavBar: View {
    @State private var showApplePolicy = false
    
    var body: some View {
        Button() {
            showApplePolicy = true
        } label: {
            Text("Apple Music and Privacy")
        }.sheet(isPresented: $showApplePolicy, content: {
            NavigationView {
                TermsAndPrivacyView()
                    .navigationTitle("Apple Music & Privacy")
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .principal) {
                            VStack {
                                Image("privacy")
                                    .resizable()
                                    .frame(width: 80, height: 65)
                                    .padding()
                                    .padding(.vertical, 20)
                                Text("Apple Music & Privacy")
                            }
                        }
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button(action: {
                                self.showApplePolicy = false
                            }) {
                                Text("Done").bold()
                            }
                        }
                    }
            }
        })
    }
}

和模态视图:

struct TermsAndPrivacyView: View {
    var body: some View {
        ScrollView {
            VStack(alignment: .center, spacing: 20) {
                Group {
                    Image("privacy")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 80, height: 65)
                        .padding()
                        .padding(.top, 20)
                        .padding(.bottom, 5)
                    Text("Apple Music & Privacy")
                        .font(.title).bold().padding(.top, -20)
                    VStack(alignment: .center) {
                        Text("Apple Music is designed to protect your information and enable you to choose what you share.")
                    }
                }
            }.padding(.horizontal, 30)
        }
    }
}

任何有关导航栏的帮助将不胜感激。

In iOS Settings > Music > Apple Music and Privacy, there is a modal that I've mostly successfully duplicated except in two ways (a brief demo of Apple's modal is here). First, I don't know how to duplicate the bullet points seen in the beginning of the text. Second, I don't know how to hide the nav bar title until scrolling past the logo and modal title. That behavior matches the .inline nav title style and suggests the logo and title are actually part of the nav bar title.

The answer here was really helpful in actually getting the nav bar to show up. I also tried using ToolbarItem and .principal from here to add an image to the toolbar, but that doesn't give the desired result. I tried adding padding because the image was squished into the nav bar but that didn't work. Lastly, I tried a VStack in the .principal placement to add the image and text below it, but that didn't work either.

Here's the code in the parent view:

struct ModalNavBar: View {
    @State private var showApplePolicy = false
    
    var body: some View {
        Button() {
            showApplePolicy = true
        } label: {
            Text("Apple Music and Privacy")
        }.sheet(isPresented: $showApplePolicy, content: {
            NavigationView {
                TermsAndPrivacyView()
                    .navigationTitle("Apple Music & Privacy")
                    .navigationBarTitleDisplayMode(.inline)
                    .toolbar {
                        ToolbarItem(placement: .principal) {
                            VStack {
                                Image("privacy")
                                    .resizable()
                                    .frame(width: 80, height: 65)
                                    .padding()
                                    .padding(.vertical, 20)
                                Text("Apple Music & Privacy")
                            }
                        }
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button(action: {
                                self.showApplePolicy = false
                            }) {
                                Text("Done").bold()
                            }
                        }
                    }
            }
        })
    }
}

and the modal view:

struct TermsAndPrivacyView: View {
    var body: some View {
        ScrollView {
            VStack(alignment: .center, spacing: 20) {
                Group {
                    Image("privacy")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 80, height: 65)
                        .padding()
                        .padding(.top, 20)
                        .padding(.bottom, 5)
                    Text("Apple Music & Privacy")
                        .font(.title).bold().padding(.top, -20)
                    VStack(alignment: .center) {
                        Text("Apple Music is designed to protect your information and enable you to choose what you share.")
                    }
                }
            }.padding(.horizontal, 30)
        }
    }
}

Any help with the nav bar would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

栀梦 2025-01-24 05:42:12

首先,这个问题应该分成多个问题。通常情况下,这会让问题结束,但这里人们只是否决了这一点。请务必阅读我在第一条评论中放置的链接,以解答将来的问题。您的问题是:

  1. 如何将两个文本或图像相邻放置并对齐?
  2. 当某个视图完全隐藏在导航栏后面时,如何隐藏和显示 .navigationTitle

在回答第一个问题时,我混合使用了 .firstTextBaseline 对齐方式和 .alignmentGuide 将文本项目符号放在正确的位置。虽然我对这些值进行了硬编码,但如果情况可能发生变化,请尽量避免使用它。在这种情况下,视图不变,因此可以接受。

至于隐藏和显示标题,我使用 PreferenceKey 读取 Text("Apple Music & Privacy") 视图底部的位置 <代码>滚动视图。当该值为零时,该视图位于导航栏后面。然后,我只需设置一个 @State 变量即可在发生这种情况时进行切换,并使用它来设置标题。

您还会注意到我将 ModalNavBar 中的所有内容都拉出了。在这种情况下,所有内容都应包含在工作表显示的视图中。它工作得更好,并且封装了一些东西,因此您只需将不同的视图放入工作表中,它仍然可以正常工作。

最后,我省略了一些文本视图以保持答案简短。请随意将它们添加回来。当您看到省略号时,这仅意味着省略了代码。

struct ModalNavBar: View {
    @State private var showApplePolicy = false
    
    var body: some View {
        Button() {
            showApplePolicy = true
        } label: {
            Text("Apple Music & Privacy")
        }.sheet(isPresented: $showApplePolicy, content: {
            NavigationView {
                TermsAndPrivacyView()
                    .toolbar {
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button(action: {
                                self.showApplePolicy = false
                            }) {
                                Text("Done").bold()
                            }
                        }
                    }
            }
        })
    }
}

struct TermsAndPrivacyView: View {
    @State var showTitle = false
    var body: some View {
        ScrollView {
            VStack(alignment: .center, spacing: 20) {
                Image(systemName: "person.3.fill")
                    .font(.system(size: 80))
                Text("Apple Music & Privacy")
                    .font(.title).bold()
                    // The PreferenceKey reads where it is within the ScrollView. "Scroll" is a coordinate space name
                    // set on the ScrollView. .maxY is simply the value of the Y dimension at the bottom of that view
                    // within the coordinates of the ScrollView. When that hits zero, it is behind the navigation bar.
                    .background(
                        GeometryReader {
                            Color.clear.preference(key: TextLocationPrefKey.self,
                                                   value: $0.frame(in: .named("Scroll")).maxY)
                        }
                    )
                Text("Apple Music is designed to protect your information and enable you to choose what you share.")
                // Put the text bullet and text together in an HStack with a .firstTextBaseline alignement
                HStack(alignment: .firstTextBaseline) {
                    Text(Image(systemName: "circle.fill"))
                        .font(.system(size: 4))
                        .opacity(0.5)
                        // The .alignmentGuide let's you tweak the actual alignment. In this case I moved it up by 2.
                        .alignmentGuide(.firstTextBaseline) { context in
                            context.height + 2
                        }
                    Text("Lorem ipsum dolor sit amet, praesent necessitatibus ei has, te sit hinc munere, ea vix fugit novum noluisse. Nulla graeci delicatissimi qui cu, nec doming iudicabit ex, indoctum partiendo an has. In qui sensibus dissentiunt, inani iudico accusamus ei eum. Suas vidit primis vel ad, meis ignota postea at pri, ei usu consul evertitur. Per vocent sadipscing et. Has debitis deterruisset ei, democritum scribentur te duo, purto accommodare id ius.")
                }

                     ...                

            }.padding(.horizontal, 30)
        }
        // This is a simple ternary condition. If showTitle is true the title is set to "Apple Music & Privacy" else ""
        .navigationTitle(showTitle ? "Apple Music & Privacy" : "")
        .navigationBarTitleDisplayMode(.inline)
        // This is where the PreferenceKey value is compared to zero to set the showTitle variable.
        .onPreferenceChange(TextLocationPrefKey.self) { textLocation in
            withAnimation(.easeIn(duration: 0.15)) {
                showTitle = !(textLocation > 0)
            }
        }
        // This is where you select and name the view for the coordinate space
        .coordinateSpace(name: "Scroll")
    }
}

// This is how the preference key is set up.
fileprivate struct TextLocationPrefKey: PreferenceKey {
    typealias Value = CGFloat
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        // This adds or subtracts based on the change in the value as you scroll the view towards the navigation
        // bar, nextValue() is negative, reducing value towards zero.
        value += nextValue()
    }
}

Firstly, This question should have been broken up into multiple questions. Normally that would have gotten the question closed, but here people only downvoted this. Make sure to read the links that I put in my first comment for future questions. Your questions are:

  1. How do I put place two texts or images next to each other and align them?
  2. How do I hide and show the .navigationTitle when a certain view is fully hidden behind the navigation bar?

In answer to the first question, I used a mix of .firstTextBaseline alignment and an .alignmentGuide to put the text bullet in the correct spot. While I hardcoded these values, try to avoid it if things can change. In this case, the view is unchanging so it is acceptable.

As to the hiding and showing the title, I used a PreferenceKey to read the location of the bottom of the Text("Apple Music & Privacy") view in the ScrollView. When that hits zero, this view is behind the navigation bar. Then I simply set a @State variable to toggle when this happens, and use that to set the title.

You will also notice I pulled everything that was in your ModalNavBar out. In a case like this, everything should be contained in the view that the sheet is displaying. It works better, and encapsulates things so you could just drop a different view into the sheet and it still works fine.

Lastly, I have omitted a bunch of text views to keep the answer brief. Feel free to add them back in. When you see the ellipsis, that simply means omitted code.

struct ModalNavBar: View {
    @State private var showApplePolicy = false
    
    var body: some View {
        Button() {
            showApplePolicy = true
        } label: {
            Text("Apple Music & Privacy")
        }.sheet(isPresented: $showApplePolicy, content: {
            NavigationView {
                TermsAndPrivacyView()
                    .toolbar {
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button(action: {
                                self.showApplePolicy = false
                            }) {
                                Text("Done").bold()
                            }
                        }
                    }
            }
        })
    }
}

struct TermsAndPrivacyView: View {
    @State var showTitle = false
    var body: some View {
        ScrollView {
            VStack(alignment: .center, spacing: 20) {
                Image(systemName: "person.3.fill")
                    .font(.system(size: 80))
                Text("Apple Music & Privacy")
                    .font(.title).bold()
                    // The PreferenceKey reads where it is within the ScrollView. "Scroll" is a coordinate space name
                    // set on the ScrollView. .maxY is simply the value of the Y dimension at the bottom of that view
                    // within the coordinates of the ScrollView. When that hits zero, it is behind the navigation bar.
                    .background(
                        GeometryReader {
                            Color.clear.preference(key: TextLocationPrefKey.self,
                                                   value: $0.frame(in: .named("Scroll")).maxY)
                        }
                    )
                Text("Apple Music is designed to protect your information and enable you to choose what you share.")
                // Put the text bullet and text together in an HStack with a .firstTextBaseline alignement
                HStack(alignment: .firstTextBaseline) {
                    Text(Image(systemName: "circle.fill"))
                        .font(.system(size: 4))
                        .opacity(0.5)
                        // The .alignmentGuide let's you tweak the actual alignment. In this case I moved it up by 2.
                        .alignmentGuide(.firstTextBaseline) { context in
                            context.height + 2
                        }
                    Text("Lorem ipsum dolor sit amet, praesent necessitatibus ei has, te sit hinc munere, ea vix fugit novum noluisse. Nulla graeci delicatissimi qui cu, nec doming iudicabit ex, indoctum partiendo an has. In qui sensibus dissentiunt, inani iudico accusamus ei eum. Suas vidit primis vel ad, meis ignota postea at pri, ei usu consul evertitur. Per vocent sadipscing et. Has debitis deterruisset ei, democritum scribentur te duo, purto accommodare id ius.")
                }

                     ...                

            }.padding(.horizontal, 30)
        }
        // This is a simple ternary condition. If showTitle is true the title is set to "Apple Music & Privacy" else ""
        .navigationTitle(showTitle ? "Apple Music & Privacy" : "")
        .navigationBarTitleDisplayMode(.inline)
        // This is where the PreferenceKey value is compared to zero to set the showTitle variable.
        .onPreferenceChange(TextLocationPrefKey.self) { textLocation in
            withAnimation(.easeIn(duration: 0.15)) {
                showTitle = !(textLocation > 0)
            }
        }
        // This is where you select and name the view for the coordinate space
        .coordinateSpace(name: "Scroll")
    }
}

// This is how the preference key is set up.
fileprivate struct TextLocationPrefKey: PreferenceKey {
    typealias Value = CGFloat
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout Value, nextValue: () -> Value) {
        // This adds or subtracts based on the change in the value as you scroll the view towards the navigation
        // bar, nextValue() is negative, reducing value towards zero.
        value += nextValue()
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文