首页 的iOS& Swift Tutorials

使用SwiftUI的watchOS的并发症

了解如何在SwiftUI中创建复杂性,这些复杂性将提高您的开发效率,提供令人愉悦的显示效果并为您的用户提供一个可单击的入口点,用于启动watchOS应用。

5/5 1个评分

  • Swift 5,iOS 14,Xcode 12

用户可以通过多种方式与Apple Watch进行交互。这些交互中的一些是触觉信号,例如在腕上短按以表示事件。其他交互更复杂,涉及到佩戴者的一些轻拍。

假设您开始跑步,沿着路走100英尺,然后记得开始锻炼。在没有配对电话为Siri供电的情况下,您需要单击Digital Crown,找到Workout应用程序,选择Outdoor Run锻炼,然后开始锻炼。尽管只花了几秒钟的时间,但感觉却很麻烦。

这就是复杂性的来源。有了复杂性,您可以为手表佩戴者提供最常用应用程序的捷径。

在本教程中,您将了解:

  • watchOS的复杂性是什么。
  • 使用SwiftUI的并发症。
  • 使用SwiftUI预览快速迭代复杂性。
  • 通过表盘表面的色彩控制复杂的色彩。
  • 提供复杂的真实数据。
  • 使用提供程序的并发症。
注意:本教程假定您已基本了解SwiftUI并可以访问Xcode 12.2或更高版本。由于您将大部分时间都花在SwiftUI画布或模拟器上,因此您无需亲自看就能完成本教程。

入门

使用 下载资料 本教程顶部或底部的链接以获取入门项目。 下一步是什么 是一个调度应用程序,可告诉您距离下一次活动还有多少时间。

该应用程序已具有关联的Watch应用程序。在本教程中,您将为Watch应用添加一些复杂功能。

解压缩档案并打开 起动机 夹。然后打开Xcode项目 下一步是什么.xcodeproj:

入门项目

The 入门项目 has a data model which consists of the struct Appointment 和 a manager class AppointmentData. Appointment supplies a list of dummy data in dummyData(). Feel free to change the data or add new items.

首先,选择要使用的iOS模拟器。选择 iPhone 12专业版Max 从目标选择器:

select 的iOSdevice

在项目导航器中,找到 下一步是什么▸视图. You’ll find the beginnings of the UI for the app. There’s not much here except a simple ListView in AppointmentList but that’s enough to work with for now.

打开 ContentView.swift。然后打开 SwiftUI 具有右上角控件或组合键的画布 命令选项返回:

显示画布

您的画布已暂停。请点击 恢复 位于画布顶部以告诉预览重新加载。或者,您可以使用组合键 Command-Option-P:

恢复画布预览

在很短的时间内,预览就会出现:

的iOSpreview

现在,选择要用于“观看”应用的模拟器。使用方案 下一步是什么WatchApple Watch Series 6 – 44毫米 模拟器。

watchOS方案

注意:如果手腕较小,则可以选择40mm模拟器。

在项目导航器中,找到 下一步是什么Watch扩展 然后选择 ContentView.swift。就像您刚才对主应用程序所做的那样,恢复画布,您将看到预览:

watchOS预览

这两个应用在两者上看起来都相似 的iOSwatchOS. They both use the same View code with a small tweak to font size between the two platforms. SwiftUI lets you easily unify your UI design across platforms.

创造并发症

在Xcode 12之前,创建复杂的程序需要经历较长的更改/构建/测试周期。现在,您可以使用SwiftUI画布预览您的复杂性。

在本节中,您将使用SwiftUI带来一些复杂性。但首先,需要介绍一些背景知识。

什么是并发症

复杂功能出现在手表的主屏幕上,显示少量信息,并可以通过点击直接访问Watch应用。

例如,在 太阳能表盘 面对下面有四个并发症。从左上方顺时针方向:

  1. 计时器:您不想再次融化咖啡机。
  2. 日期:真的是哪一天?谁能告诉?
  3. 黎明巡逻:所以您知道冲浪的最佳时间。
  4. 温度:当猫要您放火时,它们不是在开玩笑。

样品表盘

创建手表应用程序时,您需要考虑希望客户与手表进行哪些互动。您的应用程序会做什么,如何将其应用于状态变化或时间流逝的概念?

有不同类型的并发症,分为家庭。现在看看那些。

并发症家庭

并发症被安排成 家庭。有一个叫做 CLKComplicationFamily 整理这些家庭。一个家庭描述了主屏幕上的位置以及并发症的大小。创建可以充分利用可用空间的复杂功能是您的工作,还是设计师的工作。

您可能会决定对多个不同的家庭进行并发症。例如,观察 黎明巡逻 并发症 图形角 右下角的上下文:

图形角并发症

这是对空间的有效利用。它显示高/低潮汐时间和当前潮汐。现在,在 模块化大 位置:

模块化大并发症

还有更多可用空间,可以给您一些图形自由。在这种情况下,您会得到一个图形!

理论已经完成,需要一些编码使事情复杂化!

创建一个SwiftUI并发症

To make iteration quick 和 easy, you’ll use the SwiftUI preview canvas to represent the Appointment data from the app as complications. You’ll already be familiar with this process if you’ve written 的iOSor macOS apps using SwiftUI.

在项目导航器中,选择并展开 下一步是什么Watch扩展。使用组合键 Command-N 在该组中创建一个新文件。选择 SwiftUI视图 从模板窗口,然后单击 下一页:

文件模板选择器

命名文件 并发症视图 并确保将其添加到 下一步是什么Watch扩展 目标。然后点击 创造 完成添加文件:

名称 file

并发症视图.swift, add this module import below import SwiftUI:

import ClockKit

您需要这两个模块来构建复杂性并将它们显示为预览。

Then insert this code below the definition of 并发症视图:

// 1
struct ComplicationViewCircular: View {
  // 2
  @State var appointment: Appointment

  var 身体: some View {
    // 3
    ZStack {
      ProgressView(
        "\(appointment.rationalizedTimeUntil())",
        value: (1.0 - appointment.rationalizedFractionCompleted()),
        total: 1.0)
        .progressViewStyle(
          CircularProgressViewStyle(tint: appointment.tag.color.color))
    }
  }
}

该代码的作用如下:

  1. 定义一个新的结构,它将成为您的循环并发症。
  2. Pass in an Appointment instance, which is state for the view, since the view will display information about the appointment.
  3. The 身体 of the complication is simple a ZStack with a ProgressView which uses the appointment values to set it up.

Now, locate 并发症视图_Previews at the bottom of the file. Replace the 身体 of var previews with:

// 1
Group {
  // 2
  CLKComplicationTemplateGraphicCircularView(
    ComplicationViewCircular(
      appointment: Appointment.oneDummy(offset: Appointment.oneHour * 0.5)
    )
  // 3
  ).previewContext()
}

虽然这只是几行代码,但它确实繁重:

  1. You construct a so you can present many previews at once later.
  2. Then, you instantiate a CLKComplicationTemplateGraphicCircularView. Templates are a declarative way of specifying the complication’s view. This template takes one argument which is a View. 在 your case, an instance of ComplicationViewCircular which you just added, created with a dummy appointment.
  3. Most importantly, you ask the template for a previewContext. This displays the watch face that’s appropriate to the template.

那是复杂的部分(双关语意味深长),现在是时候预览它了。

预览并发症

现在,确保仍将Scheme设置为使用Watch模拟器。如果您将其设置为手机模拟器的画布,则不会加载:

watchOS方案

显示并恢复SwiftUI画布,以查看Xcode 12的一些小技巧。在首次构建时可能需要一段时间。

您可以在下一次约会之前的29分钟内看到黄色的进度视图。根据60分钟的值计算进度。

角圆并发症

Now, in 并发症视图_Previews locate:

Appointment.oneDummy(offset: Appointment.oneHour * 0.5)

将声明更改为:

Appointment.oneDummy(offset: Appointment.oneHour * 2)

您会看到预览更改为:

备用通函

这就是swiftUI画布带给watchOS开发的力量。您可以获得更改的即时结果。

注意:您可能会注意到您的计算机在渲染手表预览时非常努力。当您的计算机即将起飞时,请不要惊慌。

复杂性之旅的下一步是看看另一种复杂性,这是您在本教程前面部分实际看到的。

转角并发症

现在,您要看一下 CLKComplicationTemplateGraphicCornerCircularView 模板。此模板用于您之前看到的表盘的四个角,即:

样品表盘

关于这一点,有趣的是它们可以带有颜色。在本部分中,您将学习如何调整视图以适应这种着色渲染环境。

并发症视图.swift, add this code underneath the ComplicationViewCircular struct:

// 1
struct ComplicationViewCornerCircular: View {
  // 2
  @State var appointment: Appointment

  var 身体: some View {
    // 3
    ZStack {
      Circle()
        .fill(Color.white)
      Text("\(appointment.rationalizedTimeUntil())")
        .foregroundColor(Color.black)
      Circle()
        .stroke(appointment.tag.color.color, lineWidth: 5)
    }
  }
}

该代码的作用如下:

  1. 为此类型的并发症创建一个新的视图。
  2. 同样,您将需要传递约会。
  3. The view is a ZStack with a circle that’s filled white at the bottom, followed by text showing the time until the appointment is due, followed by a circle which is stroked with the appointment’s color.

下一页, add this code inside the of 并发症视图_Previews:

CLKComplicationTemplateGraphicCornerCircularView(
  ComplicationViewCornerCircular(
    appointment: Appointment.dummyData()[1])
).previewContext(faceColor: .red)

You now have a with two template declarations inside.

You’ve instantiated CLKComplicationTemplateGraphicCornerCircularView. Again, this template takes one View as an argument. Now the previewContext has a faceColor.

如果需要,请恢复画布。现在,您将显示两个不同的表盘。下部是红色的脸,并发症在左上方:

图形圆角

嗯您将描边圆圈的颜色设置为约会的颜色!但是这里显示为灰色!这是怎么回事?!我们需要那种颜色。

带回色彩

在这个复杂功能系列中,watchOS可以使用任何颜色的灰度值在有色环境中表示它们。您会发现您的并发症已被淘汰。如何将某些弹出窗口重新添加到视图中?

当系统对图像进行着色时,您需要区分前景和背景。您可以提供一种颜色作为SwiftUI视图修改器。

找出 身体 财产 ComplicationViewCornerCircular 和 replace the ZStack with:

ZStack {
  Circle()
    .fill(Color.white)
  Text("\(appointment.rationalizedTimeUntil())")
    .foregroundColor(Color.black)
    .complicationForeground()
  Circle()
    .stroke(appointment.tag.color.color, lineWidth: 5)
    .complicationForeground()
}

You have added complicationForeground() view-modifier to the Text 和 second Circle instances. This makes watchOS consider these views as foreground elements 和, therefore, tint them with the face color. 恢复 the canvas 和 you’ll see the result:

面部色泽并发症

现在,您已经了解了根据表盘表面的色彩为复杂的事物着色的时候,是时候学习一些有关如何在有色环境和全色环境中同时使用复杂事物的方法。

使用运行时渲染状态

What happens when you want to render your complication different ways for a tinted face 和 a full-color face. Well, you can ask EnvironmentValues for the current state.

Add this code to ComplicationViewCornerCircular below @State var appointment: Appointment:

@Environment(\.complicationRenderingMode) var renderingMode

ClockKit declares ComplicationRenderingMode 和 has two values: .tinted.fullColor. You can use these values to choose a rendering style.

ComplicationViewCornerCircular locate the first Circle in the ZStack:

Circle()
  .fill(Color.white)

Then replace that code with this switch statement:

switch renderingMode {
case .fullColor:
  Circle()
    .fill(Color.white)
case .tinted:
  Circle()
    .fill(
      RadialGradient(
        gradient: Gradient(colors: [.clear, .white]),
        center: .center,
        startRadius: 10,
        endRadius: 15))
@unknown default:
  Circle()
    .fill(Color.white)
}

Finally, add this code to the in 并发症视图_Previews:

CLKComplicationTemplateGraphicCornerCircularView(
  ComplicationViewCornerCircular(
    appointment: Appointment.oneDummy(offset: Appointment.oneHour * 3.0))
).previewContext()

现在,您在画布预览中有了第三张面孔,可显示并发症的全彩色版本。

恢复 the canvas. You’ll see that .tinted uses a RadialGradient:

并发放射状渐变色

While for .fullColor you see the original white fill:

白色填充并发症

现在,您已经了解了创建基于SwiftUI的复杂性的基础。总结一下:

  1. 创造 a SwiftUI View.
  2. Place that View in a CLKComplicationTemplate.
  3. 利润?

您已经了解了如何在画布上显示并发症的预览。稍后您将创建更多的并发症,但是现在该是时候找出如何在正在运行的应用程序中使用并发症了。

使用并发症数据源

打开 ComplicationController.swift. This is a CLKComplicationDataSource, which vends instances of CLKComplicationTemplate to watchOS on demand.

像大多数数据源模式一样,对数据源也有一些疑问:

  • 上一次已知事件的时间是几点?
  • 现在发生了什么?
  • 将来会发生什么?

回答这些问题是您的工作!

您回答第一个问题, 上一次已知事件的时间是几点?, in getTimelineEndDate(for:withHandler:).

First, add this property at the top of ComplicationController:

let dataController = AppointmentData(appointments: Appointment.dummyData())

AppointmentData acts as a manager for your list of Appointment objects.

Then, replace everything inside getTimelineEndDate(for:withHandler:) with:

handler(dataController.orderedAppointments.last?.date)

You supply the date of the last Appointment on your list.

接下来,您回答问题 现在发生了什么? in getCurrentTimelineEntry(for:withHandler:). But first, you need to set up a little help.

将此导入添加到的顶部 ComplicationController.swift:

import SwiftUI

Then add this extension to the end of the file:

extension ComplicationController {
  func makeTemplate(
    for appointment: Appointment,
    并发症: CLKComplication
  ) -> CLKComplicationTemplate? {
    switch complication.family {
    case .graphicCircular:
      return CLKComplicationTemplateGraphicCircularView(
        ComplicationViewCircular(appointment: appointment))
    case .graphicCorner:
      return CLKComplicationTemplateGraphicCornerCircularView(
        ComplicationViewCornerCircular(appointment: appointment))
    default:
      return nil
    }
  }
}

在 this method, you supply the correct template based on the CLKComplicationFamily of the CLKComplication requesting a template. For now, there’s only the two you created earlier, but you’ll add more to this method later.

Now, head to getCurrentTimelineEntry(for:withHandler:). Replace the supplied code inside with:

if let next = dataController.nextAppointment(from: 日期()),
  let template = makeTemplate(for: next, 并发症: complication) {
  let entry = CLKComplicationTimelineEntry(
    date: next.date,
    complicationTemplate: template)
  handler(entry)
} else {
  handler(nil)
}

Here you construct a CLKComplicationTimelineEntry for the current event which represents a single moment along the timeline of things happening in your app.

Each event in your app may have a corresponding CLKComplicationTimelineEntry object with a template.

未来过去的数据

数据源回答的第三个问题是 将来会发生什么? in getTimelineEntries(for:after:limit:withHandler).

Replace the code inside getTimelineEntries(for:after:limit:withHandler) with:

// 1
let timeline = dataController.appointments(after: date)
guard !timeline.isEmpty else {
  handler(nil)
  return
}

// 2
var entries: [CLKComplicationTimelineEntry] = []
var current = date
let endDate = (timeline.last?.date ?? date)
  .addingTimeInterval(Appointment.oneHour)

// 3
while (current.compare(endDate) == .orderedAscending) && 
  (entries.count < limit) {
  // 4
  if let next = dataController.nextAppointment(from: current),
    let template = makeTemplate(for: next, 并发症: complication) {
    let entry = CLKComplicationTimelineEntry(
      date: current, 
      complicationTemplate: template)
    entries.append(entry)
  }
  // 5
  current = current.addingTimeInterval(5.0 * 60.0)
}

// 6
handler(entries)

该代码的作用如下:

  1. 从数据控制器获取即将到来的约会的时间表。
  2. 您将创建一个以五分钟为间隔的时间轴条目数组。因此,创建一个数组将它们放入其中,并设置一些不久将有用的变量。
  3. 迭代不超过一小时的条目,受watchOS请求的限制。
  4. 获取下一个约会,为其创建一个复杂模板并将其添加到条目列表中。
  5. 向前跳过5分钟。
  6. 最后,将条目交给watchOS处理程序。

The reason for creating an entry spaced at each five minute interval is that it allows you to tell watchOS you want the complication updated automatically every five minutes. 如果 you don't need the periodic update for your complication, then you can return one CLKComplicationTimelineEntry for each event in your timeline.

下图显示了每五分钟有多少个条目,每个条目将显示下一个即将发生的事件。因此,“旋转类”之前的所有条目都将显示“旋转类”的数据,但是当然还有不同的时间。

并发症时间表条目

通过 implementing these three CLKComplicationDataSource methods, you've done the minimum you need to get your complication running.

现在,是时候让您的并发症在模拟器上运行并看到实际效果了!

在模拟器上运行并发症

生成并运行 下一步是什么Watch 瞄准 Apple Watch Series 6 44毫米。然后点击 数字王冠。点击并按住 主屏幕 显示编辑模式。

如果 子午线 未显示面孔,然后在整个面孔上单击并拖动以滑动来进行滑动,以更改面孔:

表盘编辑模式

现在点击 编辑 显示面部编辑器。然后在脸上滑动,直到出现面部的并发症编辑器:

并发症编辑器用户界面

接下来,单击其中一个插槽以显示并发症选择器。请点击 下一步是什么 选择它:

选择并发症

现在点击 数字王冠 两次以返回主屏幕。您的并发症会出现,显示直到您下次约会的时间:

编辑人脸最终状态

单击并发症以显示正在运行的Watch应用。整齐! :]

您已经看到了几种不同的并发症类型。现在是时候了解更多内容了。

进行更多的并发症

到目前为止,您已经了解了如何预览并发症并在实际的watchOS应用中使用它们。现在是时候应对更大的并发症,提供更多的空间了。

反应成矩形

The first template you'll create in this section is CLKComplicationTemplateGraphicRectangularFullView.

打开 并发症视图.swift 和 add this above 并发症视图_Previews:

struct ComplicationViewRectangular: View {
  @State var appointment: Appointment

  var 身体: some View {
    HStack(spacing: 10) {
      ComplicationViewCircular(appointment: appointment)
      VStack(alignment: .leading) {
        Text(appointment.name)
          .font(.title)
          // 1
          .minimumScaleFactor(0.4)
          .lineLimit(2)
          .multilineTextAlignment(.leading)
        HStack(spacing: 4.0) {
          Spacer()
          Text("at")
          // 2
          Text(appointment.date, style: .time)
        }
        .font(.footnote)
        // 3
        .complicationForeground()
      }
    }
    .padding()
    .background(
      RoundedRectangle(cornerRadius: 10.0)
        .stroke(lineWidth: 1.5)
        .foregroundColor(appointment.tag.color.color)
        .complicationForeground())
  }
}

This View is a composition of ComplicationViewCircular 和 some text. There are a few interesting things to note:

  1. You use minimumScaleFactorlineLimit to control how the title text shrinks to fit content.
  2. Notice the Text(appointment.date, style: .time). Here you use one of the built-in time formatter types to display the time at which the appointment occurs. You'll explore other formatter types soon.
  3. You use .complicationForeground() to provide display hints that you learned about earlier.

Now add these two previews to the in 并发症视图_Previews:

CLKComplicationTemplateGraphicRectangularFullView(
  ComplicationViewRectangular(
    appointment: Appointment.dummyData()[2])
).previewContext()
CLKComplicationTemplateGraphicRectangularFullView(
  ComplicationViewRectangular(
    appointment: Appointment.oneDummy(offset: Appointment.oneHour * 0.25))
).previewContext(faceColor: .orange)

这将同时添加有色和全色版本的预览:

大矩形并发症

那很快,对吗?再一次,您可以看到SwiftUI的强大功能。

盘旋问题

您是否在想这有多容易?有什么收获?

The catch is that there are things you shouldn't put in a SwiftUI based complication. You'll explore the topic of forbidden items as you build your final SwiftUI based complication for CLKComplicationTemplateGraphicExtraLargeCircularView.

首先,里面 并发症视图.swift, add the following above ComplicationViewCircular:

// 1
struct CircularProgressArc: 形状 {
  @State var progress: Double = 0.5

  func path(in rect: CGRect) -> Path {
    var path = Path()
    let limit = 0.99
    let halfarc: Double = max(0.01, min(progress, limit)) * 180.0
    path.addArc(
      center: CGPoint(x: rect.midX, y: rect.midY),
      radius: rect.width / 2,
      startAngle: .degrees(90 - halfarc),
      endAngle: .degrees(90 + halfarc),
      clockwise: true)
    return path
  }
}

// 2
struct ProgressArc<S>: ProgressViewStyle where S: 形状Style {
  // 3
  var strokeContent: S
  var strokeStyle: StrokeStyle

  init(
    _ strokeContent: S,
    strokeStyle style: StrokeStyle = 
      StrokeStyle(lineWidth: 10.0, lineCap: .round)
  ) {
    self.strokeContent = strokeContent
    self.strokeStyle = style
  }

  // 4
  func makeBody(configuration: Configuration) -> some View {
    CircularProgressArc(progress: configuration.fractionCompleted ?? 0.0)
      .stroke(strokeContent, style: strokeStyle)
      .shadow(radius: 5.0)
  }
}

这是此代码的作用:

  1. 创造 a 形状 object which can be used to draw an arc retreating from both sides of the bottom of a circle.
  2. 创造 a custom ProgressViewStyle which can be applied to a ProgressView instance to style it however you wish.
  3. There are two properties on this object. The strokeContent is any 形状Style 和 will be used to stroke the progress. This could be a Color for example. The stokeStyle indicates the style of stroke, e.g. the width of the line.
  4. The makeBody(configuration:) call returns an instance of CircularProgressArc you created above to tell the ProgressView how to draw itself.

下一页, add this code above 并发症视图_Previews:

struct ComplicationViewExtraLargeCircular: View {
  // 1
  @State var appointment: Appointment

  var 身体: some View {
    // 2
    ZStack(alignment: .center) {
      // 3
      Circle()
        .foregroundColor(appointment.tag.color.color)
      ProgressView(
        value: appointment.rationalizedFractionCompleted())
        .progressViewStyle(ProgressArc(Color.white))
        .complicationForeground()

      // 4
      ScrollView {
        VStack(alignment: .center, spacing: 3.0) {
          // 5
          Text("在 \(Text(appointment.date, style: .relative))")
            .font(.footnote)
            .minimumScaleFactor(0.4)
            .lineLimit(2)
          Text(appointment.name)
            .font(.headline)
            .minimumScaleFactor(0.4)
            .lineLimit(2)
          Text("at \(Text(appointment.date, style: .time))")
            .font(.footnote)
        }
        .multilineTextAlignment(.center)
        .foregroundColor(.black)
        .complicationForeground()
      }
    }
    .padding([.leading, .trailing], 5)
  }
}

此代码将另一个视图添加到您正在增长的集合中。在这个:

  1. Once again the Appointment is state for the view.
  2. There is a ZStack again to arrange all the items in a stack, containing:
  3. A Circle 和 a ProgressView. The ProgressView has the style applied to it which you created just now.
  4. A ScrollView which has in it a VStack with the information about the appointment

Almost done. Add these two views to the in 并发症视图_Previews:

CLKComplicationTemplateGraphicExtraLargeCircularView(
  ComplicationViewExtraLargeCircular(
    appointment: Appointment.oneDummy(offset: Appointment.oneHour * 0.2))
).previewContext()
CLKComplicationTemplateGraphicExtraLargeCircularView(
  ComplicationViewExtraLargeCircular(
    appointment: Appointment.dummyData()[2])
).previewContext(faceColor: .blue)

恢复您的画布。请注意,即使可以看到两个新面孔,也看不到复杂性,并且代码的构建没有错误。好奇!您将了解下一步的原因。

失败的并发症渲染

改正课程

那么,这种并发症为什么不起作用?打开 ComplicationController.swift. 在 makeTemplate(for:complication:) add this case to the switch statement above default::

case .graphicExtraLarge:
  return CLKComplicationTemplateGraphicExtraLargeCircularView(
    ComplicationViewExtraLargeCircular(
      appointment: appointment))

Here you return an instance of CLKComplicationTemplateGraphicExtraLargeCircularView for the .graphicExtraLarge complication family.

构建并运行。当应用程序打开时,返回主屏幕。然后长按将主屏幕再次置于编辑模式。

向左滑动,直到到达 屏幕:

添加新的面部屏幕

请点击 + 然后选择 超大 从列表中。

选择x大脸

现在,单击该面孔以将其选中。然后长按返回编辑模式。编辑脸部并选择 下一步是什么 并返回主屏幕。

失败状态

那是可悲的表盘!

您会在“运行时”部分看到此警告 问题导航器 并在控制台中:

导航器中的运行时警告

如果你打开 ComplicationController.swift, you'll the same warning on the handler(_:) call in getCurrentTimelineEntry(for:withHandler:).

打开 并发症视图.swift 和 locate ComplicationViewExtraLargeCircular. Remove the ScrollView by deleting the ScrollView { 和 its closing }. Do not remove the views the ScrollView.

恢复您的预览画布。现在您可以看到并发症:

大圆脸矫正

因此,仅提醒​​您不能将所有SwiftUI视图复杂化。它仅限于不需要用户交互的简单视图,例如文本和形状。但是您可以用这些做很多事!接下来,您将了解另一种不使用SwiftUI视图的复杂性。

SwiftUI之外的其他功能

在 this section you'll build a complication to support the .utilitarianLarge family. This family uses the CLKComplicationTemplateUtilitarianLargeFlat template, which appears as a single line across the width of the watch with text 和 an optional image, like so:

功利主义的大并发症在哪里出现

打开 ComplicationController.swift。然后,将此代码添加到文件底部:

extension ComplicationController {
  // 1
  func makeUtilitarianLargeFlat(appointment: Appointment) 
  -> CLKComplicationTemplateUtilitarianLargeFlat {
    // 2
    let textProvider = CLKTextProvider(
      format: "\(appointment.name) in \(appointment.rationalizedTimeUntil())")

    // 3
    if let bgImage = UIImage.swatchBackground(),
      let fgImage = UIImage.swatchForeground(name: appointment.tag.name),
      let onePiece = UIImage.swatchOnePiece(name: appointment.tag.name) {
      // 4
      let imageProvider = CLKImageProvider(
        onePieceImage: onePiece,
        twoPieceImageBackground: bgImage,
        twoPieceImageForeground: fgImage)
      // 5
      let complication = CLKComplicationTemplateUtilitarianLargeFlat(
        textProvider: textProvider,
        imageProvider: imageProvider)
      return complication
    } else {
      // 6
      let complication = CLKComplicationTemplateUtilitarianLargeFlat(
        textProvider: textProvider)
      return complication
    }
  }
}

这是这样做的:

  1. makeUtilitarianLargeFlat(appointment:) is a method that takes an Appointment 和 returns a CLKComplicationTemplateUtilitarianLargeFlat.
  2. 创造 a CLKTextProvider, which is essentially an object that can vend text when it's needed.
  3. 创造 three images using methods in UIImage+Lozenge.swift. These images will be used in the complication view to display a little lozenge shape with the first three letters of the appointment's tag 名称 in it.
  4. 如果 the images created successfully, create a CLKImageProvider, which will vend an image as needed to display in the complication. You can read more about this initializer on 苹果网站.
  5. Then, create a CLKComplicationTemplateUtilitarianLargeFlat with the text 和 image providers you created.
  6. 如果 the images failed to create, simply create a CLKComplicationTemplateUtilitarianLargeFlat with only the text.

还在 ComplicationController.swift, locate makeTemplate(for:complication:). Then add this case to switch above default::

case .utilitarianLarge:
  return makeUtilitarianLargeFlat(appointment: appointment)

生成并运行以查看所呈现的复杂性。加脸 活动数字。然后编辑脸部以选择 下一步是什么 并发症:

功利主义的大渲染

恭喜!您已经做了一个复杂的事情,使用提供程序而不是SwiftUI视图!

就是这样!您已经完成了本教程。现在就不复杂了!?双关打算。 :]

从这往哪儿走

您可以使用以下网址下载该项目的完整版本: 下载资料 本教程顶部或底部的按钮。

您已经看到,使用SwiftUI创造复杂性是一个简单而快速的过程,可让您快速迭代设计。为您的应用程序构建一系列复杂性时,您需要考虑以下因素:

  • 遵守简单和节俭的概念。
  • 尝试坚持形状,线条,文字和图像。
  • 确保您正在运行的代码不太占用CPU。手表硬件不是进行昂贵计算的地方。如果您需要执行复杂的算法,请在手机或后端上执行该操作,然后将结果发送至手表以进行显示。

One thing you might want to try out is working out how to get the complication picker to show something better than two dashes. Look at getLocalizableSampleTemplate(for:withHandler:) 和, if you need a hint, check out the final project which shows how to do it.

如果您的并发症过于耗电,那么watchOS会抑制它的运转,您的客户将获得不可预测的体验。

这些WWDC 2020视频是有关并发症的良好背景。

我希望您喜欢本教程。如果您有任何疑问或意见,请加入下面的讨论。

平均评分

5/5

为此内容添加评分

1个评分

更像这样

贡献者

评论