使用 List/ScrollView 与 SFSafariViewController 全屏工作表发生冲突
Posted
技术标签:
【中文标题】使用 List/ScrollView 与 SFSafariViewController 全屏工作表发生冲突【英文标题】:Conflict using List/ScrollView with SFSafariViewController fullscreen sheet 【发布时间】:2020-09-06 06:38:08 【问题描述】:我正在尝试制作一个项目列表,每个项目都应使用 SFSafariViewController 全屏打开一个工作表。为了全屏显示 SFSafariViewController,我使用了此链接中提供的代码:https://dev.to/uchcode/web-sheet-with-sfsafariviewcontroller-4nlc。控制器工作得很好。但是,当我将项目放入 List 或 ScrollView 时,它不会显示工作表。当我删除 List/ScrollView 时,它工作正常。
这里是代码。
import SwiftUI
import SafariServices
struct RootView: View, Hostable
@EnvironmentObject private var hostedObject: HostingObject<Self>
let address: String
let title: String
func present()
let config = SFSafariViewController.Configuration()
config.entersReaderIfAvailable = true
let safari = SFSafariViewController(url: URL(string: address)!, configuration: config)
hostedObject.viewController?.present(safari, animated: true)
var body: some View
Button(title)
self.present()
struct ContentView: View
@State private var articlesList = [
ArticlesList(id: 0, title: "Apple", link: "http://apple.com", lang: "en"),
ArticlesList(id: 1, title: "Yahoo", link: "http://yahoo.com", lang: "en"),
ArticlesList(id: 2, title: "microsoft", link: "http://microsoft.com", lang: "en"),
ArticlesList(id: 3, title: "Google", link: "http://google.com", lang: "en")
]
var body: some View
NavigationView
//Here is the problem when I add RootView inside a List or ScrollView it does not show Safari.
ScrollView(.vertical, showsIndicators: false)
VStack
ForEach(articlesList) article in
RootView(address: article.link, title: article.title).hosting()
Spacer(minLength: 10)
.navigationBarTitle("Articles")
struct ArticlesList: Identifiable, Codable
let id: Int
let title: String
let link: String
let lang: String
struct UIViewControllerView: UIViewControllerRepresentable
final class ViewController: UIViewController
var didAppear: (UIViewController) -> Void = _ in
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
didAppear(self)
var didAppear: (UIViewController) -> Void
func makeUIViewController(context: Context) -> UIViewController
let viewController = ViewController()
viewController.didAppear = didAppear
return viewController
func updateUIViewController(_ uiViewController: UIViewController, context: Context)
//
struct UIViewControllerViewModifier: ViewModifier
var didAppear: (UIViewController) -> Void
var viewControllerView: some View
UIViewControllerView(didAppear:didAppear).frame(width:0,height:0)
func body(content: Content) -> some View
content.background(viewControllerView)
extension View
func uiViewController(didAppear: @escaping (UIViewController) -> ()) -> some View
modifier(UIViewControllerViewModifier(didAppear:didAppear))
class HostingObject<Content: View>: ObservableObject
@Published var viewController: UIViewController? = nil
struct HostingObjectView<Content: View>: View
var rootView: Content
let hostedObject = HostingObject<Content>()
func getHost(viewController: UIViewController)
hostedObject.viewController = viewController.parent
var body: some View
rootView
.uiViewController(didAppear: getHost(viewController:))
.environmentObject(hostedObject)
protocol Hostable: View
associatedtype Content: View
func hosting() -> Content
extension Hostable
func hosting() -> some View
HostingObjectView(rootView: self)
【问题讨论】:
如果您发布编译代码,您将获得更多/更好的答案。例如,删除getArticles
函数和 LoadingView
,添加一些测试数据,并确保所有内容都可以复制/粘贴到一个新的 SwiftUI 项目中,然后立即编译。
@BartvanKuik,我编辑了问题,为新的 SwiftUI 准备了一个代码。
【参考方案1】:
您的代码可以在 ios 14 模拟器中运行!
我包装了 SFSafariViewController,如果我用以下代码替换您的 RootView
,它可以在我的 iOS 13 设备上运行。但是,它并不是真正的全屏,而是一张纸。
struct RootView: View
@State private var isPresenting = false
let address: String
let title: String
var body: some View
Button(self.title)
self.isPresenting.toggle()
.sheet(isPresented: self.$isPresenting)
SafariView(address: URL(string: self.address)!)
struct SafariView: UIViewControllerRepresentable
let address: URL
func makeUIViewController(context: Context) -> SFSafariViewController
let config = SFSafariViewController.Configuration()
config.entersReaderIfAvailable = true
let safari = SFSafariViewController(url: self.address, configuration: config)
return safari
func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context)
//
【讨论】:
如果它在 iOS 14 中工作,是否意味着它是以前版本(如 13.7)中的错误?我不确定该工作表是否适合用户。我会做一个测试。 老实说,我不知道。目前,我没有运行 iOS 14 测试版的可用设备。但在得出这是 iOS 13 错误的结论之前,我肯定想在那里对其进行测试,并且它确实适用于 iOS 14。 @BartvanKuik 嘿!你能找到解决办法吗? @KennyBatista 我希望下面的答案对您有所帮助。【参考方案2】:下面是工作代码..
import SwiftUI
import SafariServices
struct ContentView: View
var body: some View
TabView
HomeView()
.tabItem
VStack
Image(systemName: "house")
Text("Home")
.tag(0)
ArticlesView().hosting()
.tabItem
VStack
Image(systemName: "quote.bubble")
Text("Articles")
.tag(1)
struct HomeView: View
var body: some View
Text("This is home")
struct ShareView: View
var body: some View
Text("Here the share")
struct ArticlesView: View, Hostable
@EnvironmentObject private var hostedObject: HostingObject<Self>
@State private var showShare = false
@State private var articlesList = [
ArticlesList(id: 0, title: "Apple", link: "http://apple.com", lang: "en"),
ArticlesList(id: 1, title: "Yahoo", link: "http://yahoo.com", lang: "en"),
ArticlesList(id: 2, title: "microsoft", link: "http://microsoft.com", lang: "en"),
ArticlesList(id: 3, title: "Google", link: "http://google.com", lang: "en")
]
func present(address: String)
let config = SFSafariViewController.Configuration()
config.entersReaderIfAvailable = true
let safari = SFSafariViewController(url: URL(string: address)!, configuration: config)
hostedObject.viewController?.present(safari, animated: true)
var body: some View
NavigationView
ScrollView(.vertical, showsIndicators: false)
VStack(spacing: 40)
ForEach(articlesList) article in
Button(article.title)
self.present(address: article.link)
.sheet(isPresented: $showShare)
ShareView()
.navigationBarTitle("Articles")
.navigationBarItems(leading:
Button(action:
self.showShare.toggle()
)
Image(systemName: "plus")
)
struct ArticlesList: Identifiable, Codable
let id: Int
let title: String
let link: String
let lang: String
struct UIViewControllerView: UIViewControllerRepresentable
final class ViewController: UIViewController
var didAppear: (UIViewController) -> Void = _ in
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
didAppear(self)
var didAppear: (UIViewController) -> Void
func makeUIViewController(context: Context) -> UIViewController
let viewController = ViewController()
viewController.didAppear = didAppear
return viewController
func updateUIViewController(_ uiViewController: UIViewController, context: Context)
//
struct UIViewControllerViewModifier: ViewModifier
var didAppear: (UIViewController) -> Void
var viewControllerView: some View
UIViewControllerView(didAppear:didAppear).frame(width:0,height:0)
func body(content: Content) -> some View
content.background(viewControllerView)
extension View
func uiViewController(didAppear: @escaping (UIViewController) -> ()) -> some View
modifier(UIViewControllerViewModifier(didAppear:didAppear))
class HostingObject<Content: View>: ObservableObject
@Published var viewController: UIViewController? = nil
struct HostingObjectView<Content: View>: View
var rootView: Content
let hostedObject = HostingObject<Content>()
func getHost(viewController: UIViewController)
hostedObject.viewController = viewController.parent
var body: some View
rootView
.uiViewController(didAppear: getHost(viewController:))
.environmentObject(hostedObject)
protocol Hostable: View
associatedtype Content: View
func hosting() -> Content
extension Hostable
func hosting() -> some View
HostingObjectView(rootView: self)
【讨论】:
以上是关于使用 List/ScrollView 与 SFSafariViewController 全屏工作表发生冲突的主要内容,如果未能解决你的问题,请参考以下文章
在 HStack 中有 2 个 List/ScrollView 时,NavigationView 不会折叠 - SwiftUI
static与const联合使用&&extern与const联合使用
为啥将@Transactional 与@Service 一起使用而不是与@Controller 一起使用
为啥将@Transactional 与@Service 一起使用而不是与@Controller 一起使用
将 require('...') 与变量一起使用与在 webpack 中使用字符串
C 语言数组与指针操作 ( 数组符号 [] 与 指针 * 符号 的 联系 与 区别 | 数组符号 [] 与 指针 * 符号 使用效果 基本等价 | 数组首地址 与 指针 本质区别 )