备案的网站是公司吗,vs做的网站排版错位,中国体育新闻,怎样建设免费网站创建主工程就不必讲了 1 创建小组件 创建子工程 [new Target ] 选择 [ Widger Extension] 小组件入口是WidgetBundle文件#xff0c;可以进行多个小组件的调试 TestWidget2文件是主要操作#xff0c;小组件使用swiftUI布局#xff0c;使用 AppIntent进行事件处理#xff…创建主工程就不必讲了 1 创建小组件 创建子工程 [new Target ] 选择 [ Widger Extension] 小组件入口是WidgetBundle文件可以进行多个小组件的调试 TestWidget2文件是主要操作小组件使用swiftUI布局使用 AppIntent进行事件处理TestDataUserDefalut 用的userdefault 和主程序数据同步下面详细讲解
//
// TestWidget2.swift
// TestSwift6Demo
//
// Created by ITHPNB04296 on 11/3/25.
//import WidgetKit
import SwiftUI
import AppIntentsstruct TestWidget2:Widget{let kind:String TestWidget2var body: some WidgetConfiguration{StaticConfiguration(kind: kind, provider: MyWidget2Provider()) {entry inTestWidget2View(entry: entry ,ganmeStatus: entry.state).containerBackground(for: ContainerBackgroundPlacement.widget) {//背景色Color.yellow}}.configurationDisplayName(TestWidget2).description(show Testwidget2).supportedFamilies([.systemMedium])}}struct TestWidget2View:View {var entry: MyWidget2Provider.EntryEnvironment(\.widgetFamily) var family:WidgetFamilyvar ganmeStatus:Test2State
// var selectedCharacter:CharacterDetailvar body: some View {VStack{Text(\(ganmeStatus.date.description))Button(\(ganmeStatus.state)) {print(点击按钮1 直接就跳转到主APP了)}if entry.running{createRunningView()}else{createStaticView()}}}func createRunningView()-some View{//点击一次更新了一次return VStack{Button(点击按钮2, intent: Test2Intent())//该Text 无法设置停止时间
// Text(entry.date, style: Text.DateStyle.timer)
// .font(Font.system(size: 15.0))
// .fontWeight(.bold)
// .multilineTextAlignment(.center)
// .contentTransition(.numericText(countsDown: entry.state.duration 0))//新Text样式可以设置停止时间Text(timerInterval: entry.daterange,pauseTime: entry.pauseTime,countsDown: entry.countsDown,showsHours: entry.showsHours)}}func createStaticView()-some View{return VStack{Button(点击按钮2, intent: Test2Intent())Text(entry.date, style: Text.DateStyle.date).font(Font.system(size: 15.0)).fontWeight(.bold).multilineTextAlignment(.center)//过渡动画 countsDown 参数用来控制是否向下滚动.contentTransition(.numericText(countsDown: entry.state.duration 0))}}
}//添加按钮点击事件行为
struct Test2Intent:AppIntent{static var title: LocalizedStringResource XXX//点击事件函数是异步的可以做一些耗时操作比如网络请求等func perform() async throws - some IntentResult {//也可以通过App group 和主程序共享数据//点击事件更新let isrunning TestDataUserDefalut().get()TestDataUserDefalut().set(!isrunning)return .result()}
}struct Test2State{var state:Stringvar date:Date{return Date()}var duration:Int 10}struct MyWidget2Entry:TimelineEntry{var date: Date//默认区间是0var daterange:ClosedRangeDate Date()...Date()//默认没有开启var running:Bool {//添加状态控制return TestDataUserDefalut().get()}/// The relevance of a widget’s content to the user.var relevance: TimelineEntryRelevance?//添加适配新的TimerText//停止时间var pauseTime: Date Date()//倒计时var countsDown falsevar showsHours true//携带其他额外数据var state:Test2State
}struct MyWidget2Provider: TimelineProvider{//没有数据时候占位,仅初始化时候调用一次数据没加载上来时候添加占位数据func placeholder(in context: Context) - MyWidget2Entry {return MyWidget2Entry(date: Date(), state: Test2State(state: init))}//生成预览照给系统组件库使用func getSnapshot(in context: Context, completion: escaping Sendable (MyWidget2Entry) - Void) {let date Date()let entry:MyWidget2Entryprint(getSnapshot)entry MyWidget2Entry(date: date, state: Test2State(state:perview))completion(entry)}//实时更新时间线每次点击按钮时候调用两次 调用两次没理解func getTimeline(in context: Context, completion: escaping (TimelineMyWidget2Entry) - Void) {let date Date()let endtime:Date Calendar.current.date(byAdding: .minute, value: 10, to: date)!let entry MyWidget2Entry(date: date, daterange: date...endtime,countsDown: true, state: Test2State(state:start))//下一次更新时候let nextUpdateDate Calendar.current.date(byAdding: .second, value: 1, to: date)!//时间线\/*atend -当时间线中的所有条目都已显示完毕后才会重新加载时间线。固定时间点加载比如天气never - 不会自动刷新小组件内容只有主app主动去刷新数据after(Date) - 指定一个未来的日期和时间*/let timeline Timeline(entries: [entry], policy: TimelineReloadPolicy.after(nextUpdateDate))print(时间线方法1更新了 )completion(timeline)}}//更新共享数据
struct TestDataUserDefalut{func get()-Bool{let sharedDefaults UserDefaults(suiteName: group.testwidget1.demo)let isrunning sharedDefaults?.value(forKey: sharedRunning) as? Bool ?? falsereturn isrunning}func set(_ state:Bool){let sharedDefaults UserDefaults(suiteName: group.testwidget1.demo)sharedDefaults?.set(state, forKey: sharedRunning)sharedDefaults?.synchronize()}
}
小组件和主工程进行数据同步也就是进程间通信 配置 App Groups 1. 打开 Xcode选择你的主 App 目标Target。 2. 在 Signing Capabilities 中点击 Capability。 3. 搜索 App Groups 并添加。 4. 创建一个新的 App Group如 group.com.yourcompany.shared。 5. 在 Widget Extension / App Clips 目标中重复上述步骤选择相同的 App Group。
我的demo使用plist文件也就是userdefault 同步数据当然也可以使用数据库同步数据我看同事使用SwiftData(ios 17之后才能使用)同步数据 swiftData官方文档 我选择的appgroup 名字是 “group.testwidget1.demo”这个不是包名TestWidget2 里面的 TestDataUserDefalut 就是小程序同步数据代码下面看一下主程序App同步代码,添加包括刷新通知等讲解比较详细
class ViewController: UIViewController {lazy var stateLab:UILabel {let size UIScreen.main.bounds.sizelet labwidth 100.0let labheight 50.0let lab UILabel(frame: CGRectMake((size.width - labwidth) / 2.0, (size.height - labheight) / 2.0, labwidth, labheight))view.addSubview(lab)lab.backgroundColor UIColor.greenlab.font UIFont.systemFont(ofSize: 28)lab.textColor UIColor.redlab.textAlignment .centerreturn lab}()func updateState(_ state:Bool){DispatchQueue.main.async {self.stateLab.text state ? 打开 : 关闭}}func addTest(){/*配置 App Groups1. 打开 Xcode选择你的主 App 目标Target。2. 在 Signing Capabilities 中点击 Capability。3. 搜索 App Groups 并添加。4. 创建一个新的 App Group如 group.com.yourcompany.shared。5. 在 Widget Extension / App Clips 目标中重复上述步骤选择相同的 App Group。*/let appGroup group.testwidget1.demolet sharedDefaults UserDefaults(suiteName: appGroup)let isrunning sharedDefaults?.value(forKey: sharedRunning) as? Bool ?? falseupdateState(isrunning)}override func touchesBegan(_ touches: SetUITouch, with event: UIEvent?) {super.touchesBegan(touches, with: event)let sharedDefaults UserDefaults(suiteName: group.testwidget1.demo)let isrunning sharedDefaults?.value(forKey: sharedRunning) as? Bool ?? falsesharedDefaults?.set(!isrunning, forKey: sharedRunning)print(\(!isrunning))updateState(!isrunning)//通知小组件刷新notifiUpdateWidget()}func notifiUpdateWidget(){//通知小组件刷新,刷新所有小组件WidgetCenter.shared.reloadAllTimelines()//刷新指定的小组件,小组件那边注册的kind
// WidgetCenter.shared.reloadTimelines(ofKind: TestWidget1)//获取配置去刷新小组件
// WidgetCenter.shared.getCurrentConfigurations { result in
// guard case .success(let success) result else {
// return
// }
// if let widget success.first(where:{ widget inlet intent widget.configuration as ConfigurationAppIntentreturn intent?.character }){WidgetCenter.shared.reloadTimelines(ofKind: widget.kind)}
// }}override func viewDidLoad() {super.viewDidLoad()addTest()}}苹果官方小组件文档
苹果官方swiftUI文档