Apple Watch 的 WatchKit 中是否有 ActivityIndicator(或类似的东西)?你们如何向用户提供有关某些更持久的后台活动的反馈?
为了添加选项,我在 GitHub 上创建了一个
JBWatchActivityIndicator
项目,可让您生成自己的图像序列:https://github.com/mikeswanson/JBWatchActivityIndicator
如果您不想创建自己的动画,它还包括类似 Apple 的活动指示器动画。
编辑:此答案最初是在推出具有蜂窝和 WiFi 连接功能的 Apple Watch 型号之前发布的,因此可能不再适用于较新的设备型号(考虑到显着的性能改进)。
Apple 开发者论坛上的这个帖子有一位 Apple 工程师关于为什么不应该使用 Apple Watch 执行网络操作的权威答案。
不从手表应用程序/扩展程序执行网络操作有两个重要原因:
用户与手表的交互时间很短。请参阅有关此内容的人机界面指南。
如果您在几分钟内测量与 iOS 应用程序的交互,那么您可以期望在几秒钟内测量与 WatchKit 应用程序的交互。因此交互应该简短,界面应该简单。
如果网络请求没有完成,系统可能会死锁。
我们的建议是,一般来说,您不应在 WatchKit 扩展中执行复杂的网络操作...
[Apple 建议开发人员] 有一个进程负责更新数据库(可能是您的 iOS 应用程序)中的信息,然后您的扩展将(本质上)对此 [缓存] 数据库具有只读访问权限。 ..
话虽这么说。如果你确实需要一个 UIActivityIndicator,rdar://19363748 (我认为这个还没有开放雷达),开发者已经提出了官方支持的请求。
您可以按照您选择的活动指示器样式创建一系列图像,然后使用
startAnimatingWithImagesInRange:duration:repeatCount:
API 将它们设置为动画。有关 wkinterfaceimage 动画的示例,请参阅 Apple 的 Lister 应用程序。
我为 Apple Watch 构建了一个简单的活动指示器,可在此处获取 https://github.com/tijoinc/WatchActivityIndicator
SwiftUI 有一个内置的解决方案:
ProgressView()
它看起来像这样:
WatchKit Framework 中没有显示 ActivityIndicator 的方法。但是,您可以准备一些圆形图像并轻松地自己创建无限动画。 准备图像并像这样命名它们
frame-0, frame-1, frame-2...frame-n
然后在你的代码中:
[self.yourInterfaceImage setImageNamed:@"firstFrame-"]; //setting first frame
[self.yourInterfaceImage startAnimatingWithImagesInRange:[self.model imageRange]
duration:0.4
repeatCount:0];
// [self.model imageRange] will return NSRange from 0 to n
// repeatCount == 0 means infinity. Of course you can set some limit, like 100.
希望这有帮助。
我用 swiftUI 将其制作得与 watchOS 指示器类似。
import SwiftUI
struct ActivityIndicatorView: View {
// MARK: - Value
// MARK: Public
@Binding var isAnimating: Bool
// MARK: Private
private let radius: CGFloat = 24.0
private let count = 18
private let interval: TimeInterval = 0.1
private let point = { (index: Int, count: Int, radius: CGFloat, frame: CGRect) -> CGPoint in
let angle = 2.0 * .pi / Double(count) * Double(index)
let circleX = radius * cos(CGFloat(angle))
let circleY = radius * sin(CGFloat(angle))
return CGPoint(x: circleX + frame.midX, y: circleY + frame.midY)
}
private let timer = Timer.publish(every: 1.8, on: .main, in: .common).autoconnect() // every(1.8) = count(18) / interval(0.1)
@State private var scale: CGFloat = 0
@State private var opacity: Double = 0
// MARK: - View
var body: some View {
GeometryReader { geometry in
ForEach(0..<self.count) { index in
Circle()
.fill(Color.white)
.frame(width: 3.0, height: 3.0)
.animation(nil)
.opacity(self.opacity)
.scaleEffect(self.scale)
.position(self.point(index, self.count, self.radius, geometry.frame(in: .local)))
.animation(
Animation.easeOut(duration: 1.0)
.repeatCount(1, autoreverses: true)
.delay(TimeInterval(index) * self.interval)
)
}
.onReceive(self.timer) { output in
self.update()
}
}
.rotationEffect(.degrees(10.0))
.opacity(isAnimating == false ? 0 : 1.0)
.onAppear {
self.update()
}
}
// MARK: - Function
// MARK: Private
private func update() {
scale = 0 < scale ? 0 : 1.0
opacity = 0 < opacity ? 0 : 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.scale = 0
self.opacity = 0
}
}
}
#if DEBUG
struct ActivityIndicatorView_Previews: PreviewProvider {
static var previews: some View {
let view = ActivityIndicatorView(isAnimating: .constant(true))
return Group {
view
.previewDevice("Apple Watch Series 5 - 44mm")
view
.previewDevice("Apple Watch Series 4 - 40mm")
view
.previewDevice("Apple Watch Series 3 - 42mm")
view
.previewDevice("Apple Watch Series 3 - 38mm")
}
}
}
#endif
在我看来,尝试创建自己的 Spinner 正在使用过多的资源。如果苹果认为这是一个好主意,他们就会建议它。
我只想有一个可以调整 Alpha 的图像。使用布尔值来查看是否应该添加或减去 Alpha。
if (add)
{
count=count+5;
if (count==100)
{
add=false;
}
}
else
{
count=count-5;
if (count==0)
{
add=true;
}
}
float thealpha=((float)count/100);
[self.scanb setAlpha:thealpha];
}
这是一个简单的文本指示器,它使用 @State 属性:
struct MyView: View {
private let loaderSpeed = 0.1 // seconds per state
private let loaderStates = [
"• ",
" • ",
" • ",
" • ",
" • ",
" • ",
" • ",
" •",
" • ",
" • ",
" • ",
" • ",
" • ",
" • ",
]
@State private var loaderMessage = ""
@State private var loaderState = 0 {
didSet {
if self.loaderState > 0 {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + self.loaderSpeed) {
if self.loaderState > 0 {
self.loaderMessage = self.loaderStates[self.loaderState-1]
if self.loaderState >= self.loaderStates.count {
self.loaderState = 1
} else {
self.loaderState += 1
}
}
}
}
}
}
var body: some View {
HStack() {
Spacer()
Text("Loading:")
Text(loaderMessage).onAppear { self.loaderState = 1 }
Spacer()
}
}
}
设置
loaderState = 1
启动加载程序
设置
loaderState = 0
以停止装载机
使用默认的ProgressView() watchos 支持https://developer.apple.com/documentation/SwiftUI/ProgressView