SwiftUI:如何在悬停时显示工具提示/提示?

问题描述 投票:0回答:6

如何在某些视图上显示工具提示/提示? 例如,在按钮上。

tooltip swiftui
6个回答
30
投票

SwiftUI 2.0

就这么简单

   Button("Action") { }
     .help("Just do something")

   Button("Action") { }
     .help(Text("Just do something"))

19
投票

2020 | SwiftUI 1 和 2 都

在 swiftUI 2 中:

Toggle("...", isOn: $isOn)
    .help("this is tooltip")

在 swiftUI 1 中,确实没有创建工具提示的本地方法。 但这里也有一个解决方案:

import SwiftUI

@available(OSX 10.15, *)
public extension View {
    func tooltip(_ toolTip: String) -> some View {
        self.overlay(TooltipView(toolTip))
    }
}

@available(OSX 10.15, *)
private struct TooltipView: NSViewRepresentable {
    let toolTip: String
    
    init(_ toolTip: String) {
        self.toolTip = toolTip
    }
    
    func makeNSView(context: NSViewRepresentableContext<TooltipView>) -> NSView {
        NSView()
    }
    
    func updateNSView(_ nsView: NSView, context: NSViewRepresentableContext<TooltipView>) {
        nsView.toolTip = self.toolTip
    }
}

和用法:

Text("some text with tooltip")
    .tooltip("some tooltip")

7
投票

感谢 AndrewSorin 的解决方案方向。所提供的解决方案大多有效,但当我使用它们时,它们完全弄乱了布局。事实证明,工具提示有自己的大小、框架等,不会自动匹配内容。

理论上我可以通过使用固定框架等来解决这些问题,但这对我来说似乎不是正确的方向。

我想出了以下(稍微复杂一些)但易于使用的解决方案,没有这些缺点。

extension View {
    func tooltip(_ tip: String) -> some View {
        background(GeometryReader { childGeometry in
            TooltipView(tip, geometry: childGeometry) {
                self
            }
        })
    }
}

private struct TooltipView<Content>: View where Content: View {
    let content: () -> Content
    let tip: String
    let geometry: GeometryProxy

    init(_ tip: String, geometry: GeometryProxy, @ViewBuilder content: @escaping () -> Content) {
        self.content = content
        self.tip = tip
        self.geometry = geometry
    }

    var body: some View {
        Tooltip(tip, content: content)
            .frame(width: geometry.size.width, height: geometry.size.height)
    }
}

private struct Tooltip<Content: View>: NSViewRepresentable {
    typealias NSViewType = NSHostingView<Content>

    init(_ text: String?, @ViewBuilder content: () -> Content) {
        self.text = text
        self.content = content()
    }

    let text: String?
    let content: Content

    func makeNSView(context _: Context) -> NSHostingView<Content> {
        NSViewType(rootView: content)
    }

    func updateNSView(_ nsView: NSHostingView<Content>, context _: Context) {
        nsView.rootView = content
        nsView.toolTip = text
    }
}

我在工具提示的内容中添加了一个

GeometryReader
,然后限制工具提示的大小以匹配内容的大小。

使用方法:

Toggle("...", isOn: $isOn)
   .tooltip("This is my tip")

2023 年 1 月加入

最新版本的 SwiftUI 需要对

tooltip
方法进行小的改动。我注意到快速重绘问题。通过添加
ZStack
这个问题得到解决:

extension View {
    func tooltip(_ tip: String) -> some View {
        ZStack {
            background(GeometryReader { childGeometry in
                TooltipView(tip, geometry: childGeometry) {
                    self
                }
            })
            // self
        }
    }
}

2023 年 2 月:我删除了第二个自己。有了额外的自我,父母就会焕发光彩。


2
投票

当叠加层不够好时,例如你想要接受鼠标事件的控件上的工具提示(并且覆盖不允许点击),例如 Toggle,一个解决方案可能是使用内部包含 NSHostingView 本身的主机视图 - 支持作为 AppKit 视图的工具提示- 最终在内部加载更多 SwiftUI 内容:

struct Tooltip<Content: View>: NSViewRepresentable {
    typealias NSViewType = NSHostingView<Content>

    init(_ text: String?, @ViewBuilder content: () -> Content) {
        self.text = text
        self.content = content()
    }

    let text: String?
    let content: Content

    func makeNSView(context: NSViewRepresentableContext<Tooltip<Content>>) -> NSViewType {
        NSViewType(rootView: content)
    }
    func updateNSView(_ nsView: NSViewType, context: NSViewRepresentableContext<Tooltip<Content>>) {
        nsView.rootView = content
        nsView.toolTip = text
    }
}

当与某些 SwiftUI 内容一起使用时,这确实有一些关于调整大小的警告(然后您可能希望使用 fixedSize() 或 frame(width:height:) 让它根据需要工作),但它在其他方面很容易使用:

Tooltip("A description") { 
    Toggle("...", isOn: $isOn) 
}

0
投票
struct TooltipText: View {
    @State private var isActive = false
    
    let text: String
    let helpText: String
    var body: some View {
        Text(isActive ? helpText : text)
            .padding( isActive ? 6 : 0)
            .background(Color.white)
            .overlay(
                RoundedRectangle(cornerRadius: 3)
                    .stroke(Color.blue, lineWidth: isActive  ? 1 : 0)
            )
            .animation(.easeOut(duration: 0.2) )
            .gesture(DragGesture(minimumDistance: 0)
                        .onChanged( { _ in isActive = true } )
                        .onEnded( { _ in isActive = false } )
            )
    }
}

使用:

TooltipText(text: "sum of squares:", helpText: "sum of data (with mean subtracted) squared")

0
投票

您也可以在界面生成器中执行此操作(在 Xcode 中以图形方式布置您的视图)。当您添加按钮时,“身份检查器”选项卡 - 屏幕右侧面板上默认“属性检查器”的前一个选项卡......还有一个“工具提示”字段。

© www.soinside.com 2019 - 2024. All rights reserved.