TipKit:如何将Tip与SwiftUI或UIKit集成?

7lrncoxx  于 2023-08-02  发布在  Swift
关注(0)|答案(2)|浏览(192)

现在苹果已经发布了TipKit,应该可以在Xcode 15 beta 5上工作了,我不知道如何将Tip与视图集成?
我有以下代码:

import SwiftUI

struct TipKitTestView: View {
    var body: some View {
        VStack {
            Text("Some filler text")
            UselessTip()
        }
    }
}

struct UselessTip: Tip {
    var title: Text {
        Text("Useless title")
    }
    
    var message: Text {
        Text("Some useless message that is a bit longer than the title.")
    }
}

字符串
编译器不喜欢我在TipKitTestView中有UselessTip(),给出了错误:Static method 'buildExpression' requires that 'UselessTip' conform to 'View' .如何获取要编译的代码?我不知道如何使提示视图,如果这有任何意义。
顺便说一下,什么代码可以使提示在UIKit中工作?我试图将Tips添加到我的项目中,并结合使用SwiftUI和UIKit代码,因此我不知道如何将Tips集成到主要使用UIKit代码的项目中。有人知道怎么做吗?

txu3uszq

txu3uszq1#

有几件事你需要做:
1.在Build Settings的Other Swift Settings中添加-external-plugin-path $(SYSTEM_DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/usr/lib/swift/host/plugins#$(SYSTEM_DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server
1.导入TipKit,然后在你的Appbody中添加一个task来配置

var body: some Scene {
        WindowGroup {
            ContentView()
                .task {
                    try? await Tips.configure()
                }
        }
    }

字符串
1.创建Tip

public struct PickNumbersTip: Tip {
    
    @Parameter
    static var hasGeneratedNumbers: Bool = false
    
    public var id: String {
        return "tip.identifier.pick-numbers"
    }
    
    public var title: Text {
        return Text("tip.title.pick-numbers", comment: "Pick Numbers Tip Title")
    }
    
    public var message: Text? {
        return Text("tip.message.pick.numbers", comment: "Pick Numbers Tip Message")
    }
    
    public var asset: Image? {
        return Image(systemName: "hand.tap")
    }
    
    public var actions: [Action] {
        [
            Action(
                id: "action.title.dismiss",
                title: String(localized: "action.title.dismiss", comment: "Dismiss")
            ),
            Action(
                id: "action.title.try-now",
                title: String(localized: "action.title.try-now", comment: "Try Now")
            )
        ]
    }
    
    public var rules: [Rule] {
        #Rule(Self.$hasGeneratedNumbers) { $0 == false } // User has never generated numbers, which makes this tip eligible for display.
    }
    
    public var options: [TipOption] {
        [Tips.MaxDisplayCount(1)]
    }
    
}


1.将其添加到View

struct ContentView: View {
    
    @State private var viewModel = ContentViewModel()
    
    private var pickNumbersTip = PickNumbersTip()
    private var generatedNumbersTip = GeneratedNumbersTip()
    
    var body: some View {
        VStack {
            
            HStack {
                ForEach(0..<viewModel.latestNumbers.count, id: \.self) { i in
                    BallView(number: viewModel.latestNumbers[i])
                }
            }
            .popoverTip(generatedNumbersTip, arrowEdge: .top) { action in
                if action.id == "action.title.dismiss" {
                    generatedNumbersTip.invalidate(reason: .userClosedTip)
                }
                if action.id == "action.title.find-out-more" {
                    generatedNumbersTip.invalidate(reason: .userPerformedAction)
                    UIApplication.shared.open(URL(string: "https://developer.apple.com/documentation/gameplaykit/gkrandomdistribution")!)
                }
            }
            
            Spacer()
            Button(action: {
                viewModel.latestNumbers = LottoGenerator.new()
                PickNumbersTip.hasGeneratedNumbers = true
                GeneratedNumbersTip.hasGeneratedNumbers = true
                GeneratedNumbersTip.countOfGeneratedNumbers.donate()
            }, label: {
                Text("button.title.pick-numbers", comment: "Pick Numbers")
            })
            .buttonStyle(.borderedProminent)
            .popoverTip(pickNumbersTip, arrowEdge: .bottom) { action in
                if action.id == "action.title.dismiss" {
                    pickNumbersTip.invalidate(reason: .userClosedTip)
                }
                if action.id == "action.title.try-now" {
                    pickNumbersTip.invalidate(reason: .userPerformedAction)
                    PickNumbersTip.hasGeneratedNumbers = true
                    viewModel.latestNumbers = LottoGenerator.new()
                    GeneratedNumbersTip.hasGeneratedNumbers = true
                    GeneratedNumbersTip.countOfGeneratedNumbers.donate()
                }
            }
        }
        .padding()
        .task {
            for await status in pickNumbersTip.shouldDisplayUpdates {
                print("Pick Numbers Tip Display Eligibility: \(status)")
            }
        }
        .task {
            for await status in generatedNumbersTip.shouldDisplayUpdates {
                print("Generated Numbers Tip Display Eligibility: \(status)")
            }
        }
    }
    
    private struct BallView: View {
        
        var number: Int
        
        var body: some View {
            ZStack {
                Circle()
                    .foregroundStyle(.red)
                
                Text(verbatim: "\(number)")
                    .bold()
                    .fontWidth(.condensed)
                    .foregroundStyle(.white)
            }
        }
    }
    
}


工作示例应用程序可在这里:https://github.com/stuartbreckenridge/TipKitSample

8ftvxx2r

8ftvxx2r2#

虽然TipKit主要是用SwiftUI编写的,但Apple提供了UIKit和AppKit实现。
要在UIKit中实现一个技巧,你可以这样做:

struct SearchTip: Tip {
    var title: Text {
        Text("Add a new game")
    }
    
    var message: Text? {
        Text("Search for new games to play via IGDB.")
    }
    
    var asset: Image? {
        Image(systemName: "magnifyingglass")
    }
}

class ExampleViewController: UIViewController {
    var searchButton: UIButton
    var searchTip = SearchTip()

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        Task { @MainActor in
            for await shouldDisplay in searchTip.shouldDisplayUpdates {
                if shouldDisplay {
                    let controller = TipUIPopoverViewController(searchTip, sourceItem: searchButton)
                    present(controller)
                } else if presentedViewController is TipUIPopoverViewController {
                    dismiss(animated: true)
                }
            }
        }
    }
}

字符串
Apple还提供了通过TipUIViewTipUIPopoverViewControllerTipUICollectionViewCell实现UIKit的进一步文档。我还写了一篇关于如何使用integrate TipKit with SwiftUI or UIKit的文章。

相关问题