iOS | iWatch开发 没有转圈的数据请求 是没有灵魂的

2020-03-07  本文已影响0人  BinaryBang

表弟最近在开发一个独立的iWatch手表应用,需要应用独立地调用接口去请求数据,而不是和iPhone通信来交换数据.
调接口请求数据本身没什么问题,NSURLSessionDataTask类不仅适用于iPhone,iWatch也能使用.所以AFNetworking等常规请求库,是可以直接使用的.

但是,有一个问题比较尴尬.
平时我们在网络请求时,都会转个圈,提示用户,我正在请求数据.

虽然很多用户神烦这个转圈,但是转圈真的很重要:

iPhone上还有专门的UIActivityIndicatorView来处理这个事情.
但是WatckKit中,没有哇...
表弟有点想让请求中按钮变灰的方式来对应.

作为一个优雅的程序员,不允许这样的事情发生.
所以,这一次我们来让菊花(转圈)在Watch应用中绽放!

1 Demo说明

本文的目标,是创建一个实现以下的基本功能的应用:
点击按钮->请求接口->转圈->收到数据->转圈消失,解析数据,显示Table.
基本的流程如下图:



最终效果:



这个gif目前只能播放一遍,需要刷新以下才能观看,原因还在调查中.

2 WatchApp如何显示动态图片

WatchKit中,播放图片的组件是WKInterfaceImage,详细信息可以参考这篇官方文档译文:WKInterfaceImage-官方文档译文

gif文件实际上是一系列图片的组合,不能和jpg或者png那样,直接播放,需要进行额外的处理.这里介绍两种方式播放gif文件:

2.1 把gif资源放在WatchKitApp资源目录

```
[interfaceImage setImageNamed:@"loading"];
[interfaceImage startAnimating];
```

2.2 程序自动提取gif的每一帧

/*
name:要播放的gif图片名;
duration:在多少时间内放完;
*/
- (UIImage *)gifImageNamed:(NSString *)name duration:(NSInteger)duration {
   //获取资源文件的路径
   NSString * path = [[NSBundle mainBundle] pathForResource:name ofType:nil];
   if(!path){
       NSLog(@"文件不存在!");
       return nil;
   }
   //加载NSData图片数据
   NSData * data = [NSData dataWithContentsOfFile:path];
   CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
   size_t count = CGImageSourceGetCount(source);
   if (count <= 1) {
       return [[UIImage alloc] initWithData:data];
   }
   NSMutableArray *images = [NSMutableArray array];
   
   for (size_t i = 0; i < count; i++) {
       //在栈中创建一个图片数据结构
       CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL);
       if (!imageRef) {
           continue;
       }
       //根据图片数据结构,创建一个UIImage对象
       [images addObject:[UIImage imageWithCGImage:imageRef]];
       
       //释放已经生成了UIImage对象的图片数据结构
       CGImageRelease(imageRef);
   }
   
   UIImage *animatedImage = [UIImage animatedImageWithImages:images duration:duration];
   
   CFRelease(source);
   
   return animatedImage;
}
[self.ifImage setImage:[self gifImageNamed:@"wait.gif" duration:2]];
[self.ifImage startAnimating];

3 WKInterfaceTable的使用

WatchKit中的表视图是WKInterfaceTable类,相比于UITableView,使用上简化了很多.

3.1 Cell的配置

WKInterfaceTable将负责Cell显示的类,叫做TableRowController,我们需要自定义一个类来承担TableRowController这样的角色.
TableRowController被关联了一个Group,用来对cell上面要呈现的空间进行布局.我们可以将这些控件关联到TableRowController对应的类上,进行控制.

#import <WatchKit/WatchKit.h>
@interface TableCell : NSObject
@property (weak, nonatomic) IBOutlet WKInterfaceLabel *ifLabel;
@end

这样,cell就配置好了.

3.2 Table的配置

cell配置完毕之后,就是配置Table了.

    //假如要显示4个Cell
    [table setNumberOfRows:4 withRowType:@"TableCell"];

注意,这里要指定RowController的Type,需要和3.1.4中设置的保持一致.

    //arr是标题的字符串数组.
    for(int i = 0; i < table.numberOfRows;i++) {
        TableCell * cell = [table rowControllerAtIndex:i];
        NSString * title = arr[I];
        [cell.ifLabel setText:title];
    }
- (void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex {
     NSString * title = self.arr[rowIndex];
    NSLog(@"Click %@",title);
}

这样,table也设置好了.

4 WKInterfaceGroup的使用

在显示转圈的时候还有一个问题.

我们在转圈的时候,转圈的图片和Table的位置其实是在一个位置的,在没有数据时,显示转圈图片,隐藏Table;在有数据时,显示Table,隐藏转圈图片.

但是在WatchKit的InterfaceController中,一般只能竖直向下排列,不能两个控件占用同一个位置.只有InterfaceGroup提供了内容元素的布局功能;

InterfaceGroup的内容包含3中布局方式,Horizontal,Vertical,Overlap.

但是,我们希望在Table的下方有个返回的按钮,这就不能让Table和返回按钮一起在这个Overlap的Group里,否则他们会互相重叠.

所以,最终的方案是:

最后还有一点需要注意,在数据返回之后,Table的高度发生了变化需要让Overlap的Group重新调整一下高度,否则不能滚动:

[self.ifGroupRoot sizeToFitHeight];

5 真机请求时的一个大坑

在模拟器调式的时候,很顺利,得到了预期的效果.
但是在真机调式的时候,总是提示"The Internet connection appears to be offline".

这个问题让我头疼了好久.

最终发现可能的原因:

最终解决的办法是: 让配对的手机关机,飞行模式,或者接触配对.

6 总结

iWatch开发目前相关资料不是那么充足,一路上遇到了很多问题.希望记录下这些问题作为总结,并帮助有需要的人.

项目源代码放到百度网盘上了:
链接:https://pan.baidu.com/s/1jq2lTw3zU-nTsgN2EHQjrw
密码:fdih
运行环境:Xcode 11.3.1
模拟器应该可以直接运行,跑真机的话要注意本文的第5点.

如果这篇文章帮到了你,请点赞,关注,鼓励一下哈~~~

参考资料

1.WKInterfaceImage-官方文档译文

上一篇 下一篇

猜你喜欢

热点阅读