天天品尝iOS7甜点 :: Day 12 :: Dynamic Type and Font Descriptors

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


Introduction - 介绍

iOS7中介绍一个高级的有关文本渲染的框架叫做TextKit.TextKit是建立在强大的CoreText上的渲染引擎,并且现在所有的Apple提供的有关文本的组件都是已经更新到TextKit引擎上面了。TextKi添加到iOS中具有很重大的意义,其中一点就是它的动态类型的概念和字体描述符。今天本文将会来看看这些TextKit的新特性。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Dynamic Type - 动态类型

动态类型的概念是允许用户指定他们设备中应用程序内部的字体类型有多大。这并不是单单的改变字体大小的能力,而且也概念了其他的类型属性例如字距和行间距。这就确保文本的可读性,因为它可以自动设置不同的类型大小。为了做到这一点,你不需要指定文本类型的字体,而是使用语义表示。也就是不需要指定Helvetica 11pt,你需要把这些类型设置在文本主体中。这就有点类似于HTML中的标签表示,允许用户控制外观。因此,也不需要提前设置字体的大小,在UIFont中有一个新的方法可以用来纠正字体:

1
self.subHeadingLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];

天天品尝iOS7甜点 :: Day 11 :: UIView Key-frame Animations

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


Introduction - 介绍

从iOS2开始,UIView就有了实现动画的方法,而在iOS4中就添加了运用block的方法。这些方法都是对CoreAnimation层的一个装饰方法,UIView只是通过实例渲染的。

UIView中的实现动画的方法允许一下可以设置为动画的属性(例如transform, backgroundColor, frame, center等)——设置成为最终状态,运行时长和其他的一些运动曲线的选项。然而,设置中间动画的中间状态(被称之为关键帧),是不可能办到的。在这种情况下有必须运用CoreAnimation来创建一个CAKeyFrameAnimation.在iOS7中包含了这些变化,在UIView中新增了两个方法,所以不需要自己借助于CoreAnimation就可以实现关键这动画了。

为了展示如何通过UIView来实现关键帧动画,我们需要创建一些示例程序。首先通过彩虹的颜色改变视图背景颜色的动画,其次演示一个指定旋转方向的360旋转示例。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Rainbow Changer - 彩虹变色器

UIView的关键帧动画需要用到两个方法,首先一个比较熟悉的block方法是animateKeyframesWithDuration:delay:options:animations:completion:这个方法需要浮点类型的动画持续时长(duraiton)和延迟(delay),一些二进制组成的选项(options)和动画运行的block和动画运行完成最后的block,这是一个标准的UIView的动画的实现。下一次有点儿不同的方法我们称之为内部块方法:addKeyframeWithRelativeStartTime:relativeDuration:。这个方法是用来添加动画序列内的不动点。

天天品尝iOS7甜点 :: Day 10 :: Custom UIViewController Transitions

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


一些被要求的新特性为用户之间切换不同视图控制器的定制动画效果,针对UINavigationController栈和模态表示。iOS7中介绍此动能——这两种自动转换和互动转换(这些转换是用户来进行控制的)。今天本文就看介绍自动转换是如何工作的,并且实现navigation controller上面的push和pop一个平滑的效果。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

自定义转换的世界中充满了协议。然而,例如我们要创建只需要查看一小部分。要进行交互转换和模态展示交互,需要一些额外的协议。

在一个视图控制器中使用push和pop转换,我们需要确定那些转换是我们需要用到的,UINavigationControl有一个delegate可能供使用。这个delegate必须是UINavigationControllerDelegate协议,它具有4个新的方法提供个转换使用。我们感兴趣的是当前是能够提供给我们进行自一定转换的方法:

1
2
3
4
- (id<UIViewControllerAnimatedTransitioning>)navigationController:
animationControllerForOperation:
fromViewController:
toViewController:

当navigation controller进行视图转换(不管是自己写的程序还是storyboard中segue)的时候都会调用这个方法。我们被告知视图控制器从哪个到哪个的过滤,所以在这一点上我们可以进行不同的转换效果。

我们创建一个类,来扮演navigation controller代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@interface SCNavControllerDelegate : NSObject <UINavigationControllerDelegate>
@end
```

<!-- more -->

有一个很简单的实现:

``` objc
@implementation SCNavControllerDelegate
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
return [SCFadeTransition new];
}
@end
```

我们希望所有的转换都是相同的(不管是前进还是后退),所以我们可以每一次都返回一个`SCFadeTransition`对象.我们将会在下一阶段看看这个对象到底是什么。

设置这个delegate是非常简单的,代码如下所示:

``` objc
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
_navDelegate = [SCNavControllerDelegate new];
self.delegate = _navDelegate;
}
return self;
}

这里的_navDelegateid<UINavigationControllerDelegate>的一个实例。

Creating a custom transition

我们发现那个delegate需要返回一些转换对象。那些返回的转行对象必须实现了UIViewControllerAnimatedTransitioning协议。这个协议里面有3个方法,其中2个方法是必须要实现的:

  • transitionDuration:(必要).这个方法返回动画的时长。这是使用的操作系统同步其他事件——如动画导航栏导航控制器。
  • animateTransition:(必要).这个方法是你用来真实的实现视图控制器之间转换的实现。我们提供了一个对象,让我们获得我们需要的不同组件。
  • animationEnded:这个方法是在你的转换完成之后进行调用。

我们目前只需要实现2个必要的方法来让我们的平滑的转换工作,创建一个对象来实现协议:

1
2
@interface SCFadeTransition : NSObject <UIViewControllerAnimatedTransitioning>
@end

实现transitionDuration:方法,实现体十分的简单:

1
2
3
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 2.0;
}

animateTransition:方面被调用的时候,我们就得到一个实现了UIViewControllerContextTransitioning协议的对象,它能够使我们获得完成动画所需要的细节内容。我们要用到的第一个方法是viewControllerForKey:,这个方法可能允许我们获得两个视图控制器来实现转换:

1
2
3
// Get the two view controllers
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

这个上下文对象还提供了一个UIView来执行动画,这个是通过这个方法获得的containerView:

1
2
// Get the container view - where the animation has to happen
UIView *containerView = [transitionContext containerView];

我们需要确保转换的视图控制器的视图是上述视图(containerView)的子视图。就像我们转换的就是子视图而已。

1
2
3
// Add the two VC views to the container
[containerView addSubview:fromVC.view];
[containerView addSubview:toVC.view];

我们不需要看到要转换到的那个视图,所以我们需要把它设置为透明:

1
toVC.view.alpha = 0.0;

现在我们到了真正要实现动画的地方了,由于我们需要在两个视图控制器上面实现一个简单的平滑效果,我们可以使用UIView中的动画函数:

1
2
3
4
5
6
7
8
9
10
11
12
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
options:0
animations:^{
toVC.view.alpha = 1.f;
}
completion:^(BOOL finished) {
// Let's get rid of the old VC view
[fromVC.view removeFromSuperview];
// And then we need to tell the context that we're done
[transitionContext completeTransition:YES];
}];

Summary - 总结

与我们做的!它实际上是相当简单协议。我们唯一要做的就是设置已经存在的navigation view controller的delegate。剩下的工作是实现delegate类,设置一个过渡对象,然后执行动画效果。

本文翻译自:iOS7 Day-by-Day :: Day 10 :: Custom UIViewController Transitions

天天品尝iOS7甜点 :: Day 9 :: Device Identification

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


今天我们的文章将会比较的简短,但是对于那些想通过设备唯一标识ID跟踪用户的开发者来说确实十分重要的.有很多的理由你需要获得用户的设备唯一标识ID,然后这个涉及到用户的个人隐私,用户并没有授权你获得这个ID。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

设备的UDID在iOS5中已经标记为过时了,在iOS7中已经被移除了,iOS6中介绍替代方法,下面就是一个我们提供的仅有的方法:

Vendor Identification

最接近替代uniqueIdentifier的是另外一个方法,在UIDevice中的identifierForVendor,它返回NSUUID.在相同的设备里面相同供应商的app共享一个UUID.不同的供应商在同一个设备上面将会返回不同的identifierForVendor值,就像相同供应商在不同设备上面一样。

对于开发者来说,这个值提供了和原来相似的功能,而且没有用户隐私的问题。

但是美中不足的是如果用卸载了供应商下面所有的app,这个id就会被销毁,重新安装之后就会生成一个新的供应商ID。

Advertising Identification

如果你需要唯一标识ID来实现app内广告。就会有另外的一个替代方法。ADSupprt模块包含了ASIdentifierManager类,它有一个advertisingIdentifier方法。它返回一个NSUUID可以用来达到追踪广告的目的。还有一个方法avertisingTrackingEnable.它返回一个BOOL类型的数据用来指定是否用户允许进行广告追踪。如果返回值为NO,然后就有一小部分事情,app可用使用这个ID,没有涉及到跟踪用户。

广告标识是独特的在整个设备——所以,如果启用了跟踪广告可以为特定的用户定制的。往往一个应用程序开发人员不需要与这个类交互,而是将该广告服务框架在幕后使用ASIdentifierManager类。

Network Identification

当 uniqueIdentifier 被弃用了,通过使用MAC地址变得很流行。一个MAC地址是恒定不变的且唯一的,可以用来跟踪用户。但是在iOS7中Apple对这个也添加了限制,所以实际返回的MAC地址为: 02:00:00:00:00:00. 关闭这个“漏洞”,将会推动开发者运用Apple提供的优先方法来进行获得设备标识.

Conclusion

Apple压缩了获得设备标识的替代方案,所以要开始适配新的方法。这种做法对终端用户的隐私起到了很好的保护。是很值得做的。

本文翻译自:iOS7 Day-by-Day :: Day 9 :: Device Identification

天天品尝iOS7甜点 :: Day 8 :: Reading list with SafariServices

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


Introduction - 介绍

阅读列表的概念很简单-通过在你的浏览器中你看到一篇文章,但是没有时间去阅读它。阅读列表就是一种暂时的数钱页面,可以让你稍后阅读文章,在App store中有各种各样的第三方的软件,但是在iOS7中,Safari中的SafariServices开发了一个对外的API接口.

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Usage - 使用

使用Safari的阅读列表是比较简单的-在API中包含了3个方法。一个阅读列表元素由一个URL,一个标题和一个描述信息组成。URL通常是http或者https格式的,你可以用supportsURL:来检测URL的合法性:

1
2
3
if ([SSReadingList supportsURL:[NSURL urlFromString:@"http://sample/article/url"]]) {
NSLog(@"URL is supported");
}

天天品尝iOS7甜点 :: Day 7 :: Taking Snapshots of UIViews

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


Introduction - 介绍

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

有一些情况你需要得到UIView对象的快照,为了提高分享快照应用程序的性能。已经存在的方法目前遭遇一下一些问题:

  • 代码并不是十分的简单
  • 复杂的渲染选项,例如层就很难复制
  • OpenGL代码层需要特别的代码
  • 制作快照的过程详单缓慢

事实上,并没有制作快照的通用代码可供复制使用。

但是在iOS7上面,一切变得如此简单,在UIViewUIScreen中的新方法可能很简单的实现多种效果的快照功能。

天天品尝iOS7甜点 :: Day 6 :: Tint Color

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


UIView中一个相对来说比较小的属性,tintColor属性是相当的强大。今天我们就来看看如何使用他,包含使用tint color进行着色标准控件、我们自定义控件甚至重新着色图像。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Tint color of existing iOS controller - 使用tint color为iOS中已经存在的控件进行着色

在iOS7中,UIView新增了一个属性tintColor.这是一个UIColor,被使用在UIView中改变应用程序的外观的。默认tintColor的值为nil,这表示它将会运用父视图层次的颜色来进行着色。如果父视图中没有设置tintColor,那么默认系统就会使用蓝色。因此,可以通过设置root view controller的tintColor来改变系统整体的颜色。

为了证明这一点,我们需要知道tintColor如何改变标准控件的外观,可以看看我们已经写好的ColorChanger应用程序。

天天品尝iOS7甜点 :: Day 5 :: UIDynamics with Collection Views

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


回顾前面的章节,我们介绍了动态UIKit的物理引擎,并且我们使用来创建了一个牛顿的实验,尽管那个非常的有趣,但是对于创建一个应用程序来说,并不是十分的明显。今天我们就来做一个实际的应用把物理引擎添加到UICollectionViews中,形成一些明显的效果。

本章的项目就是做一个水平的有弹性的旋转木马,然后会添加他们的动态效果。

完成的代码已经在github可供下载使用:github.com/ShinobiControls/iOS7-day-by-day

为了在一个collection view上面展示物理的效果。首先,我们需要用UICollectionView创建一个旋转木马。本篇并不是着重介绍UICollectionView的教程,所以我们将会跳过创建的部分。我们将会设置collection view的代理(delegate)和数据源(datasource),实现的方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pargma mark - UICollectionViewDataSource methods
- (NSIneteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [_collectionViewCellContent count];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
SCCollectionViewSampleCell *cell = (SCCollectionViewSampleCell *)[self.collectionView dequeuqReusableCellWithReuseIdentifier:@"SpringyCell" forIndexPath:indexPath];
cell.numberLabel.text = [NSString stringWithFormat:@"%d", [_collectionViewCellContent[indexPath.row] integerValue]];
return cell;
}

#pragma mark - UICollectionViewDelegate methods
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return itemSize;
}

天天品尝iOS7甜点 :: Day 4 :: AVSpeechSynthesizer

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


介绍

自动iOS5发布之后,语音合成就是siri的一部分了,但是它没有暴露出可用功能的公共API。iOS7改变了这些,开放了一个简单的API - AVSpeechSynthesizer

完成的代码已经在github可供下载使用:github.com/ShinobiControls/iOS7-day-by-day

Voices - 语音

iOS7中包含了不同的种类的语音可以用来进行语音合成,你自己指定不同合成的语言。AVSpeechSynthesisVoce:speechVoices返回一组可用的语音集合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2013-07-12 10:49:26.929 GreetingSpeaker[31267:70b] (
"[AVSpeechSynthesisVoice 0x978a0b0] Language: th-TH",
"[AVSpeechSynthesisVoice 0x977a450] Language: pt-BR",
"[AVSpeechSynthesisVoice 0x977a480] Language: sk-SK",
"[AVSpeechSynthesisVoice 0x978ad50] Language: fr-CA",
"[AVSpeechSynthesisVoice 0x978ada0] Language: ro-RO",
"[AVSpeechSynthesisVoice 0x97823f0] Language: no-NO",
"[AVSpeechSynthesisVoice 0x978e7b0] Language: fi-FI",
"[AVSpeechSynthesisVoice 0x978af50] Language: pl-PL",
"[AVSpeechSynthesisVoice 0x978afa0] Language: de-DE",
"[AVSpeechSynthesisVoice 0x978e390] Language: nl-NL",
"[AVSpeechSynthesisVoice 0x978b030] Language: id-ID",
"[AVSpeechSynthesisVoice 0x978b080] Language: tr-TR",
"[AVSpeechSynthesisVoice 0x978b0d0] Language: it-IT",
"[AVSpeechSynthesisVoice 0x978b120] Language: pt-PT",
"[AVSpeechSynthesisVoice 0x978b170] Language: fr-FR",
"[AVSpeechSynthesisVoice 0x978b1c0] Language: ru-RU",
"[AVSpeechSynthesisVoice 0x978b210] Language: es-MX",
"[AVSpeechSynthesisVoice 0x978b2d0] Language: zh-HK",
"[AVSpeechSynthesisVoice 0x978b320] Language: sv-SE",
"[AVSpeechSynthesisVoice 0x978b010] Language: hu-HU",
"[AVSpeechSynthesisVoice 0x978b440] Language: zh-TW",
"[AVSpeechSynthesisVoice 0x978b490] Language: es-ES",
"[AVSpeechSynthesisVoice 0x978b4e0] Language: zh-CN",
"[AVSpeechSynthesisVoice 0x978b530] Language: nl-BE",
"[AVSpeechSynthesisVoice 0x978b580] Language: en-GB",
"[AVSpeechSynthesisVoice 0x978b5d0] Language: ar-SA",
"[AVSpeechSynthesisVoice 0x978b620] Language: ko-KR",
"[AVSpeechSynthesisVoice 0x978b670] Language: cs-CZ",
"[AVSpeechSynthesisVoice 0x978b6c0] Language: en-ZA",
"[AVSpeechSynthesisVoice 0x978aed0] Language: en-AU",
"[AVSpeechSynthesisVoice 0x978af20] Language: da-DK",
"[AVSpeechSynthesisVoice 0x978b810] Language: en-US",
"[AVSpeechSynthesisVoice 0x978b860] Language: en-IE",
"[AVSpeechSynthesisVoice 0x978b8b0] Language: hi-IN",
"[AVSpeechSynthesisVoice 0x978b900] Language: el-GR",
"[AVSpeechSynthesisVoice 0x978b950] Language: ja-JP"
)

天天品尝iOS7甜点 :: Day 3 :: Background Fetch

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


介绍

iOS7介绍了一个新的多任务APIs - 之前我们介绍了运用NSURLSession进行后台数据传输,不管你的app是否处与运行状态中。另外一个新的API特性是后台提取,它可以让app进行更新内容,不管app是否正在运行。这样就可以使你的app在第二次打开的时候就已经更好好了内容,iOS可以很智能的更绝你app使用情况进行后台提取工作,并且可以节省电池寿命。例如它可以注意到你每天醒来就会上社交网络,所以它就会事先自己提取好你想要的信息。

完成的代码已经在github可供下载使用:github.com/ShinobiControls/iOS7-day-by-day

Enabling background fetch - 开启后台提取功能

如果app希望注册使用后台提取功能,你可以在Xcode5的capabilities页签中设置,并且非常的简单:

,