灵动岛玩法

1,636 阅读3分钟

简介

苹果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了灵动岛。灵动岛将 iPhone 前置镜头和软件通知结合在一起的全新设计,用出色的交互设计掩盖硬件的缺陷,是一次交互玩法的革新。灵动岛可以通过点按、长按、轻扫来进行交互,最多支持两个应用同时“登岛”。

灵动岛全称 Dynamic Island,作为 iOS 中实时活动(Live Activities)功能的一部分,用来展示需要实时更新的消息。例如外卖配送信息,地图实时导航信息等。灵动岛有 3 种展现形式。

  • 紧凑(Compact)

当系统只有 1 个实时活动的内容时,灵动岛默认使用紧凑模式。紧凑模式下UI由头部(Leading side)和尾部(Trailing side)组成,如图所示。用户可以点击灵动岛打开 App 查看实时活动的内容。

  • 最小化(Minimal)

当系统有多个实时活动的内容时,灵动岛自动切换使用最小化模式。最小化模式下由附着的头部(Leading(attached))和分割开的尾部(Trailing(detached))组成,如图所示。和紧凑模式一样,最小化模式也支持用户点击打开 App。

  • 扩展(Expanded)

当用户在紧凑或最小化模式轻扫或长按灵动岛时,灵动岛可以切换成扩展模式。用于向用户展示更多信息。扩展模式的 UI

UI适配

灵动岛使用了44点的圆角半径

机型屏幕尺寸Compact leadingCompact trailingMinimal (diameter)Expanded (height given as a range)Lock Screen
iPhone 14 Pro Max430 × 932 px62.33x36.6762.33x36.6736.67408x84–160408x160
iPhone 14 Pro393 × 852 px52.33x36.6752.33x36.6736.67371x84–160371x160

开发框架

暂时无法在飞书文档外展示此内容

工程创建

Include Live Activity 这个要勾选,这个是灵动岛要用到的

Include Configuration Intent 如果你的 widget 支持用户配置属性,则需要勾选这个(例如天气组件,用户可以选择城市),不支持的话则不用勾选

在主工程的 info.plist 文件中添加 Supports Live Activities 并且设置为 YES

  • 数据部分

    •   继承ActivityAttributes,定义常用的数据来控制或改变UI及状态。这里包含的商品的基本信息,可以认为是不变的状态,可变的状态需要在 ContentState 中声明。
    • public struct BPLiveActivitiesData: ActivityAttributes {
          public typealias LiveActivitiesStatus = ContentState
          
          public struct ContentState: Codable, Hashable {
              var name: String
              var status : Int //1待接单, 2配送中 3已完成
              var timer: ClosedRange<Date>
          }
          
          var numberOfPizzas: Int
          var totalAmount: String
          var orderNumber: String
      }
      
  • 布局

  • 继承Widget,通过ActivityConfiguration来管理锁屏及灵动岛的布局
  •  struct BeautyPlusDynamicIslandLiveActivity: Widget {
        var body: some WidgetConfiguration {
            ActivityConfiguration(for: BPLiveActivitiesData.self) { context in
                // Lock screen/banner UI goes here
                // Lock screen/banner UI goes here
                VStack {
                    Text(timerInterval: context.state.timer, countsDown: true)
                        .bold()
                        .font(.caption)
                        .foregroundColor(.white.opacity(0.8))
                        .multilineTextAlignment(.center)
                    Text(context.state.name).foregroundColor(Color.white)
                }
                .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")
                        // more content
                    }
                } compactLeading: {
                    Text("L")
                } compactTrailing: {
                    Text("T")
                } minimal: {
                    Text("Min")
                }
                .widgetURL(URL(string: "http://www.apple.com"))
                .keylineTint(Color.red)
            }
        }
    }
    
  • 小组件初始化入口

    • @main
      struct BeautyPlusDynamicIslandBundle: WidgetBundle {
          var body: some Widget {
              BeautyPlusDynamicIsland()
              BeautyPlusDynamicIslandLiveActivity()
          }
      }
      
  • 数据更新

    •   Task{
               let data = BPLiveActivitiesData.LiveActivitiesStatus(name: "变化了", 
               status: 1, timer: Date()...Date().addingTimeInterval(60 * 60))
               
               for activity in Activity<BPLiveActivitiesData>.activities {
                   await activity.update(using: data)
               }
           }
      

参考链接‘

ActivityKit官方文档

设计规范