【问题标题】:SwiftUI - Hiding a ScrollView's indicators makes it stop scrollingSwiftUI - 隐藏 ScrollView 的指示器使其停止滚动
【发布时间】:2019-11-30 14:28:16
【问题描述】:

我试图隐藏 ScrollView 的指示符,但当我尝试这样做时,ScrollView 不再滚动。如果这很重要,我正在使用 macOS。

ScrollView(showsIndicators: false) {
    // Everything is in here
}

【问题讨论】:

  • 看起来只有 macOS 的缺陷。在 iOS 和 macCatalyst 上它可以工作。
  • 我遇到了同样的问题,并希望它能在 macOS 10.15.1 和 Xcode 11.2 中得到修复。由于内容不再滚动,我还看到它仍然在顶部具有弹跳效果(有时也是如此)。
  • 我面临同样的问题。在 iOS 上运行良好,但无法在 macOS 和 macCatalyst 上运行。 @Asperi - 你说它正在使用 macCatalyst - 你能展示你的代码吗?
  • @SoOverIt,见答案。
  • 这在 Big Sur 中已修复,但在 10.15.7 中仍未修复

标签: swift macos swiftui


【解决方案1】:

应@SoOverIt 的要求

演示:

没什么特别的,只是启动了一些其他的测试示例。 Xcode 11.2 / macOS 10.15

var body : some View {

    VStack {
        ScrollView([.vertical], showsIndicators: false) {
            Group {
            Text("AAA")
            Text("BBB")
            Text("CCC")
            Text("DDD")
            Text("EEE")
            }
            Group {
            Text("AAA")
            Text("BBB")
            Text("CCC")
            Text("DDD")
            Text("EEE")
            }
            Group {
            Text("AAA")
            Text("BBB")
            Text("CCC")
            Text("DDD")
            Text("EEE")
            }
            Group {
            Text("AAA")
            Text("BBB")
            Text("CCC")
            Text("DDD")
            Text("EEE")
            }
        }
        .frame(height: 100)
        .border(Color.blue)
    }
    .border(Color.red)
}

【讨论】:

  • 这很奇怪!我将您的代码复制并粘贴到一个新的 macCatalyst 应用程序中 - 仍然出现滚动错误。我正在使用 Xcode 11.3.1 和 macOS 10.15.3。我有以前使用它的记忆 - 也许它在 11.3.1 上很无聊?请参阅下面的视频答案。
【解决方案2】:

我解决了这个问题。

extension View {
    func hideIndicators() -> some View {
        return PanelScrollView{ self }
    }
}

struct PanelScrollView<Content> : View where Content : View {
    let content: () -> Content

    var body: some View {
        PanelScrollViewControllerRepresentable(content: self.content())
    }
}

struct PanelScrollViewControllerRepresentable<Content>: NSViewControllerRepresentable where Content: View{
    func makeNSViewController(context: Context) -> PanelScrollViewHostingController<Content> {
        return PanelScrollViewHostingController(rootView: self.content)
    }

    func updateNSViewController(_ nsViewController: PanelScrollViewHostingController<Content>, context: Context) {
    }

    typealias NSViewControllerType = PanelScrollViewHostingController<Content>

    let content: Content


}

class PanelScrollViewHostingController<Content>: NSHostingController<Content> where Content : View {

    var scrollView: NSScrollView?

    override func viewDidAppear() {
        self.scrollView = findNSScrollView(view: self.view)
        self.scrollView?.scrollerStyle = .overlay
        self.scrollView?.hasVerticalScroller = false
        self.scrollView?.hasHorizontalScroller = false
        super.viewDidAppear()
    }

    func findNSScrollView(view: NSView?) -> NSScrollView? {
        if view?.isKind(of: NSScrollView.self) ?? false {
            return (view as? NSScrollView)
        }

        for v in view?.subviews ?? [] {
            if let vc = findNSScrollView(view: v) {
                return vc
            }
        }

        return nil
    }
}

预览:

struct MyScrollView_Previews: PreviewProvider {
    static var previews: some View {
        ScrollView{
            VStack{
                Text("hello")
                Text("hello")
                Text("hello")
                Text("hello")
                Text("hello")
            }
        }.hideIndicators()
    }
}

【讨论】:

  • 希望他们能尽快修复它,但这暂时可行。我不会考虑这个,只是复制意大利面,谢谢!
  • 好吧,这个修复也给我带来了@ObservedObject 重新渲染视图的问题……不知道该怎么做才能防止这种情况发生。
  • @neptunes 同样在这里...不再更新视图。不能用这个
【解决方案3】:

所以...我认为这是目前唯一的方法。

您基本上只是在您的ScrollView 指示器上放置一个View,并使用与您的背景相同的backgroundColor View

注意:这显然只适用于您的背景是静态且后缘没有内容的情况。

想法

struct ContentView: View {
    
    @Environment(\.colorScheme) var colorScheme: ColorScheme
    
    let yourBackgroundColorLight: Color = .white
    let yourBackgroundColorDark: Color = .black

    var yourBackgroundColor: Color { colorScheme == .light ? yourBackgroundColorLight : yourBackgroundColorDark }
    
    
    var body: some View {
        ScrollView {
            VStack {
                ForEach(0..<1000) { i in
                    Text(String(i)).frame(width: 280).foregroundColor(.green)
                }
            }
        }
        .background(yourBackgroundColor) //<-- Same
        .overlay(
            HStack {
                Spacer()
                Rectangle()
                    .frame(width: 10)
                    .foregroundColor(yourBackgroundColor) //<-- Same
            }
        )
    }
}

精简版

你可以这样改进,我想你已经在资产中动态设置了你的颜色。

用法:

ScrollView {
    ...
}
.hideIndicators(with: <#Your Color#>)

实施:

extension View {
    func hideIndicators(with color: Color) -> some View {
        return modifier(HideIndicators(color: color))
    }
}


struct HideIndicators: ViewModifier {
    let color: Color
    
    func body(content: Content) -> some View {
        content
            .overlay(
                HStack {
                    Spacer()
                    Rectangle()
                        .frame(width: 10)
                        .foregroundColor(color)
                }
            )
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    相关资源
    最近更新 更多