灵动岛简介
注意:
兼容版本 iOS 16.1 或更高版本
iPhone的灵动岛(Dynamic Island)功能是随着 iPhone 14 Pro 和 iPhone 14 Pro Max 的推出而首次亮相的,它在刘海屏区域提供动态的提醒和活动状态,如音乐播放、录音、导航等。
灵动岛需要 iOS 16.1 或更高版本 来支持,实现实时活动(Live Activities)的功能。
灵动岛非常适合展示一下实时信息,比如:
-
计时应用
-
当前播放的音乐内容
-
实时导航信息
-
外卖进度
灵动岛样式
灵动岛有三种渲染模式:
第一种是 紧凑型,当你的应用使用灵动岛时:
第二种叫 最小型样式,是当你的应用和别人的应用都在使用灵动岛时,会显示成下面这种样式,系统会决定展示哪个 App 的灵动岛,并使用每个活动的最小演示显示两个实时活动:
第三种是 展开的灵动岛样式,当用户触摸并按住紧凑或最小的演示文稿时,它会显示,这种样式可以显示更多的内容:
灵动岛配置
1.添加小组件扩展
操作路径:Xcode -> File -> New -> Target
一定要勾选 Include live Activity
2.灵动岛权限配置
2.1) OC项目
项目要启用灵动岛,需要在 Info.plist 文件中声明开启。
打开 Info.plist 文件添加 NSSupportsLiveActivities,并将其布尔值设置为 YES。
2.2) Swift项目
打开 Targets -> Build Settings -> Info.plist Values -> Supports Live Activities,并将其布尔值设置为 YES。
3.代码部分
创建完项目后,会生成一个灵动岛小组件文件
3.1) ActivityAttributes
主要代码分为两部分,一部分是 ActivityAttributes,主要用来提供灵动岛上展示的数据:
struct MyWidgetAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var emoji: String
}
// Fixed non-changing properties about your activity go here!
var name: String
}
3.2) Widget
另一部分是灵动岛的 UI 展示
struct MyWidgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: MyWidgetAttributes.self) { context in
// Lock screen/banner UI goes here
VStack {
Text("\(context.attributes.name) \(context.state.emoji)")
}
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)
} dynamicIsland: { context in
DynamicIsland {
// Expanded UI goes here. Compose the expanded UI through
// various regions, like leading/trailing/center/bottom
DynamicIslandExpandedRegion(.leading) {
Text("Leading")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Trailing")
}
DynamicIslandExpandedRegion(.bottom) {
Text("Bottom \(context.state.emoji)")
Text("内容:\(context.attributes.name) 自定义内容")
}
} compactLeading: {
Text("L")
} compactTrailing: {
Text("T \(context.state.emoji)")
} minimal: {
Text(context.state.emoji)
}
.widgetURL(URL(string: "http://www.apple.com"))
.keylineTint(Color.red)
}
}
}
-
ActivityConfiguration 的第一个 block 用来渲染展示锁屏页面的 UI,dynamicIsland 就是用来渲染灵动岛的内容了。
-
DynamicIsland 对象中,第一部分用来渲染展开样式的 UI,compactLeading 用来展示紧凑型样式左边 UI,compactTrailing 用来展示紧凑型样式右边 UI,minimal 用来展示最小型样式 UI。
启动灵动岛
在主 App 的 ViewController 中渲染三个按钮来模拟用户达到某个条件后 启动/更新和关闭 灵动岛:
import UIKit
import ActivityKit
class ViewController: UIViewController {
var activity: Activity<MyWidgetAttributes>? = nil
override func viewDidLoad() {
super.viewDidLoad()
createButton(title: "启动灵动岛", y: view.center.y - 100, selector: #selector(start))
createButton(title: "更新灵动岛", y: view.center.y - 50, selector: #selector(update))
createButton(title: "关闭灵动岛", y: view.center.y, selector: #selector(end))
}
private func createButton(title: String, y: CGFloat, selector: Selector) {
let button = UIButton(type: .system)
button.setTitle(title, for: .normal)
button.sizeToFit()
view.addSubview(button)
button.center.x = view.center.x
button.frame.origin.y = y
button.addTarget(self, action: selector, for: .touchUpInside)
}
@objc
private func start() {
// 创建灵动岛
let attributes = MyWidgetAttributes(name: "iOS 新知")
let state = MyWidgetAttributes.ContentState(emoji: "😄")
let content = ActivityContent<MyWidgetAttributes.ContentState>(state: state, staleDate: nil)
do {
self.activity = try Activity<MyWidgetAttributes>.request(attributes: attributes, content: content)
} catch let error {
print("出错了:\(error.localizedDescription)")
}
}
@objc
private func update() {
let state = MyWidgetAttributes.ContentState(emoji: "😂")
Task {
await activity?.update(using: state)
}
}
@objc
private func end() {
Task {
await activity?.end()
}
}
}
-
启动灵动岛需要创建一个 ActivityAttributes 和一个 ActivityContent,然后调用
request(attributes: content:)方法既可,这个方法会返回一个 Activity 对象,我们保留这个对象,后面更新和关闭灵动岛的时候使用。 -
更新灵动岛只需要使用上边的 Activity 对象,调用
update(using:)方法。 -
关闭灵动岛只需要使用上边的 Activity 对象,调用
end()方法。
效果
当我们启动 App,点击【启动灵动岛】按钮,把应用退到后台(前台不展示),就可以看到灵动岛上出现了我们设置的 UI:
然后锁屏,推送通知区域会看到出现了我们渲染的内容:
长按灵动岛,可以从紧凑模式变成扩展模式:
点击灵动岛可以打开 App,点击 【更新灵动岛】按钮 ,再次退到后台,可以看到灵动岛已经刷新了:
参考文档
本文同步自微信公众号 "程序员小溪" ,这里只是同步,想看及时消息请移步我的公众号,不定时更新我的学习经验。