SwiftUI中如何让文本内链接触发Sheet弹窗?
解决方案
要实现点击文本中的“Terms of Service”和“Privacy Policy”分别打开对应Sheet弹窗,你可以通过以下两种方式修改代码:
方案一:拆分文本片段(直观易实现)
将原文本拆分为普通文本和可点击的文本片段,给可点击部分添加点击手势触发Sheet显示,同时保持与原样式一致:
import SwiftUI // 自定义的条款弹窗视图 struct showTermsofService: View { var body: some View { Text("Terms of Service Content") .padding() .navigationTitle("Terms of Service") } } // 自定义的隐私政策弹窗视图 struct showPrivacyPolicy: View { var body: some View { Text("Privacy Policy Content") .padding() .navigationTitle("Privacy Policy") } } struct ContentView: View { @State private var showTermsSheet = false @State private var showPrivacySheet = false // 统一样式参数 private let customFont = Font.custom("Nunito-Regular", size: 12) private let textColor = Color.gray private let linkColor = Color.blue var body: some View { HStack(alignment: .center, spacing: 4) { Text("By signing up, you agree to our") .font(customFont) .foregroundColor(textColor) Text("Terms of Service") .font(customFont) .foregroundColor(linkColor) .underline() .onTapGesture { showTermsSheet = true } Text("and our") .font(customFont) .foregroundColor(textColor) Text("Privacy Policy") .font(customFont) .foregroundColor(linkColor) .underline() .onTapGesture { showPrivacySheet = true } Text(".") .font(customFont) .foregroundColor(textColor) } .padding(.horizontal, 30) .multilineTextAlignment(.center) // 绑定条款Sheet .sheet(isPresented: $showTermsSheet) { NavigationStack { showTermsofService() } } // 绑定隐私政策Sheet .sheet(isPresented: $showPrivacySheet) { NavigationStack { showPrivacyPolicy() } } } }
方案二:使用AttributedString(适合复杂文本)
通过AttributedString给指定文本添加自定义链接标识,再通过onOpenURL识别点击动作,无需拆分文本:
import SwiftUI struct showTermsofService: View { var body: some View { Text("Terms of Service Content") .padding() .navigationTitle("Terms of Service") } } struct showPrivacyPolicy: View { var body: some View { Text("Privacy Policy Content") .padding() .navigationTitle("Privacy Policy") } } struct ContentView: View { @State private var showTermsSheet = false @State private var showPrivacySheet = false private let customFont = Font.custom("Nunito-Regular", size: 12) private let textColor = Color.gray private let linkColor = Color.blue // 构建富文本 private var attributedText: AttributedString { var string = AttributedString("By signing up, you agree to our Terms of Service and our Privacy Policy.") // 全局文本样式 string.font = customFont string.foregroundColor = textColor // 设置条款文本的链接样式与自定义标识 if let range = string.range(of: "Terms of Service") { string[range].foregroundColor = linkColor string[range].underlineStyle = .single string[range].link = URL(string: "internal://terms") } // 设置隐私政策文本的链接样式与自定义标识 if let range = string.range(of: "Privacy Policy") { string[range].foregroundColor = linkColor string[range].underlineStyle = .single string[range].link = URL(string: "internal://privacy") } return string } var body: some View { Text(attributedText) .padding(.horizontal, 30) .multilineTextAlignment(.center) // 识别自定义链接并触发Sheet .onOpenURL { url in switch url.host { case "terms": showTermsSheet = true case "privacy": showPrivacySheet = true default: break } } .sheet(isPresented: $showTermsSheet) { NavigationStack { showTermsofService() } } .sheet(isPresented: $showPrivacySheet) { NavigationStack { showPrivacyPolicy() } } } }
内容的提问来源于stack exchange,提问作者SLE
相关产品推荐
相关产品推荐

