iOS开发系列--通知与消息机制

在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情。iOS中通知机制又叫消息机制,其包括两类:一类是本地通知;另一类是推送通知,也叫远程通知。两种通知在iOS中的表现一致,可以通过横幅或者弹出提醒两种形式告诉用户,并且点击通知可以会打开应用程序,但是实现原理却完全不同。今天就和大家一块去看一下如何在iOS中实现这两种机制,并且在文章后面会补充通知中心的内容避免初学者对两种概念的混淆。

mac显示隐藏文件夹

打开终端,输入:defaults write com.apple.finder AppleShowAllFiles -bool true 此命令显示隐藏文件defaults write com.apple.finder AppleShowAllFiles -bool false 此命令关闭显示隐藏文件
命令运行之后需要重新加载Finder:快捷键option+command+esc,选中Finder,重新启动即可

删除Xcode插件

直接进入插件所在的目录,将插件删除即可。

插件路径为:~/Library/Application Support/Developer/Shared/Xcode/Plug-ins Library文件夹(即资源库)默认是隐藏的,所以你可以使用一下方法打开该路径:

Finder 前往->前往文件夹(快捷键cmd+Shift+G),输入以上路径,回车,找到Fuzzy Aotocomplete插件,删除。

移动UI/UX设计师和PM使用的原型工具

【编者按】本文转载自个人博客—羽化博客,原作者通过对页面原型设计的理解来介绍四款原型设计工具。
与一般针对产品功能的介绍不同,本文以亲身的设计需求为出发点,通过对产品整理和提供相关的链接,帮助解决从业人群对做产品页面原型的直接需求。可以为做产品设计的童鞋提供一些参考和下载帮助。
天天和产品打交道,不时要做一些页面原型、离不开各种工具,工欲善其事必先利其器,好的工具软件可以大大提高工作效率,工具各有优劣,大家按需取之。原型设计工具我暂时把它分为两类,Web应用原型设计工具及软件应用原型设计工具、微软的visio就不说了:
Web应用原型设计工具:先来看看这个几个:Axure RPBalsamiq MockupsPencil
Project
以及OmniGraffle试用感觉:

###第一个、Axure RP:

来这里看看视频简介:http://www.axure.com/tour.aspx

  • Axure的发音是”Ack-sure”,RP则是”Rapid Prototyping”快速原型的缩写。Axure RP Pro是美国Axure Software Solution公司的精心杰作,可以说Axure是Windows上最出色的原型设计软件,亦是web产品前期设计的首选,原因是:够简单、上手快,能帮助网站需求设计者,快捷而简便的创建 基于目录组织的原型文档、功能说明、交互界面以及带注释的wireframe网页,并可自动生成用于演示的网页文件和word文档,以提供演示与开发;
  • Axure RP六合一功能:网站构架图、示意图、流程图、交互设计、自动输出网站原型、自动输出word格式规格文件;
  • 国内都有很多教程了,看看这些:悠识网站的教程
  • Windows版:http://axure.cachefly.net/AxureRP-Pro-Setup.exe
    MAC版:http://axure.cachefly.net/AxureRP-Pro-Setup.dmg
    Axure6.5汉化语言包下载地址:http://www.axure.us/283/

###第二个、Balsamiq Mockups:

Balsamiq Mockups 视频简介

  • Balsamiq Mokups是用Flex和Air实现的,在Mac OS, Linux和Windows下都能使用,有桌面版本、Confluence,JIRA,和XWiki中的版本;
  • 涂鸦风格、使用起来也很简单、各模块工具也很齐全,详细说明可见官方博客:http://www.balsamiq.com/blogs


  • 有人提到不能输入中文的问题,很简单:在Mockups的菜单里选择 View -> Use System Font 就可以了;
  • 该软件的桌面版售价78美刀。作者意大利人Peldi说这款软件的设计就是用它自己来设计的,满足自己的需求。而在经济寒冷的2008年,从1,322位付费用户那获得了162,302美元的收入(其中12月份就有39,000美元);
  • windows版本下载地址 http://www.balsamiq.com/download

###
第三个、Pencil Project:

- 查看官网简介:http://www.evolus.vn/Pencil/Screenshots.html

###第四个、OmniGraffle

欢迎使用CSDN-markdown编辑器

安装soucetree后,启动
1添加账户.
这里写图片描述
设置托管主机,用户名,密码,协议方式
这里写图片描述
2.克隆到本地
点击远程,这时就可以看见远程仓库中内容
这里写图片描述
点击克隆,选择要克隆的目标路径,与克隆名称,点击克隆
这里写图片描述
3.在本地管理项目
点击已经克隆到本地的项目
这里写图片描述
此时是在主分支master分支下
双击一条远程分支
这里写图片描述
将其他的远程分支克隆到本地

APP间的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
被调用的App:
1.在appdelegate里实现方法

-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
{
NSLog(@"%@",app);
NSLog(@"%@",url);
NSLog(@"%@",options);
return YES;
}

2.配置Info.plist文件



调用方法:

//打开另一个APP的方法
//a另一个APP的openurl
//aaaaaaaaa参数
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"a:aaaaaaa"]];

AVAudioPlayer

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#import <AVFoundation/AVFoundation.h>

//初始化三个按钮

//play
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:button];
button.backgroundColor = [UIColor yellowColor];
[button setFrame:CGRectMake(100, 100 + 64, 60, 40)];
[button setTitle:@"play" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button addTarget:self action:@selector(play) forControlEvents:UIControlEventTouchUpInside];



//pause暂停
UIButton * button1 = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:button1];
button1.backgroundColor = [UIColor yellowColor];
[button1 setFrame:CGRectMake(100, 150 + 64, 60, 40)];
[button1 setTitle:@"pause" forState:UIControlStateNormal];
[button1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button1 addTarget:self action:@selector(pause) forControlEvents:UIControlEventTouchUpInside];



//stop
UIButton * button2 = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:button1];
button2.backgroundColor = [UIColor yellowColor];
[button2 setFrame:CGRectMake(100, 200 + 64, 60, 40)];
[button2 setTitle:@"stop" forState:UIControlStateNormal];
[button2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button2 addTarget:self action:@selector(stop) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button2];




// 从bundle路径下读取音频文件
NSString * string = [[NSBundle mainBundle] pathForResource:@"凭什么说-刘心" ofType:@"mp3"];
// 把音频文件转换成url格式
NSURL * url = [NSURL fileURLWithPath:string];
// 初始化音频类 并且添加播放文件
self.avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
// 设置代理
[self.avAudioPlayer setDelegate:self];
// 设置初始音量大小
[self.avAudioPlayer setVolume:1];
// 设置音乐播放次数 -1为一直循环
[self.avAudioPlayer setNumberOfLoops:-1];
// 预播放
[self.avAudioPlayer prepareToPlay];



// 初始化一个播放进度条
self.progressV = [[UIProgressView alloc] initWithFrame:CGRectMake(80, 100, 200, 20)];
[self.progressV setProgressTintColor:[UIColor redColor]];
[self.progressV setTrackTintColor:[UIColor blueColor]];
[self.view addSubview:self.progressV];
[self.progressV release];

// 用NSTimer来监控音频播放进度
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(playProgress) userInfo:nil repeats:YES];



// 初始化音量控制
self.volumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(80, 130, 200, 20)];
[self.volumeSlider addTarget:self action:@selector(volumeChange) forControlEvents:UIControlEventValueChanged];
// 设置最小音量
[self.volumeSlider setMinimumValue:0.0f];
// 设置最大音量
[self.volumeSlider setMaximumValue:10.0f];
// 初始化音量为多少
[self.volumeSlider setValue:5.0f];
[self.view addSubview:self.volumeSlider];
[self.volumeSlider release];


//声音开关控件(静音)
UISwitch *swith = [[UISwitch alloc] initWithFrame:CGRectMake(100, 500, 60, 40)];
[self.view addSubview:swith];
[swith addTarget:self action:@selector(onOrOff:) forControlEvents:UIControlEventValueChanged];
//默认状态为打开
swith.on = YES;
[swith release];

/********************AVAudioPlayer***************/
//播放
- (void)play
{
[self.avAudioPlayer play];
}
//暂停
- (void)pause
{
[self.avAudioPlayer pause];
}
//停止
- (void)stop
{
self.avAudioPlayer.currentTime = 0; //当前播放时间设置为0
[self.avAudioPlayer stop];
}
//播放进度条
- (void)playProgress
{
//通过音频播放时长的百分比,给progressview进行赋值;
self.progressV.progress = self.avAudioPlayer.currentTime/self.avAudioPlayer.duration;
}
//声音开关(是否静音)
- (void)onOrOff:(UISwitch *)sender
{
self.avAudioPlayer.volume = sender.on;
}

//播放音量控制
- (void)volumeChange
{
self.avAudioPlayer.volume = self.volumeSlider.value;
}

//播放完成时调用的方法 (代理里的方法),需要设置代理才可以调用
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[self.timer invalidate]; //NSTimer暂停 invalidate 使...无效;
}
/********************AVAudioPlayer***************/

BOOL / bool / Boolean / NSCFBoolean

1
NameTypedefHeaderTrue ValueFalse ValueBOOLsigned charobjc.hYESNObool_Bool (int)stdbool.htruefalseBooleanunsigned charMacTypes.hTRUEFALSENSNumber__NSCFBooleanFoundation.h@(YES)@(NO)CFBooleanRefstructCoreFoundation.hkCFBooleanTruekCFBooleanFalse

Core Animation 3D介绍(第1部分)

尊重原创 转自:http://codingobjc.com/blog/2013/06/11/core-animation-3djie-shao-di-1bu-fen/

在本教程中,我将向你介绍Core Animation中用于绘制3D图形的一些技术。
我要告诉你的好消息是:我们不必直接使用OpenGL,仅仅用Core Animation就可以很容易的实现一些3D效果。但是,也别太高兴了,因为”用Core Animation来制作一个复杂的3D游戏”也并不是一个好主意。
这个教程分两部分。第一部分,我们先讨论下一些3D原理知识,然后运用这些概念来创建一些简单的3D场景。然后在第二部分中,我们将使用Core Animation来制作一个类似于旋转木马的3D场景特效。
最终app的预览效果如下:(译注: 原文中这里的视频被墙,因此这里只简单的提供一个图片预览,你可以直接下载例子代码运行即可以看到最终app的效果)

好,准备好了吗?我们开始写代码吧!
首先,下载文章后面的代码。如果你要自己创建项目的话,要记得添加QuartzCore框架。

###3D和矩阵相关的数学知识(一点点…别担心,只有一点点)
要在一个3D空间中绘图,除了标准2D坐标(X和Y)概念外,我们还需要引入一个深度(depth)的概念,也就是要加入第三个坐标轴–Z轴。
这样,在空间中,我们只需要简单的改变物体的X、Y和Z坐标,就可以在垂直方向、水平方向或深度方向上移动物体。

在2D或3D空间中,对一个物体执行平移、缩放或旋转这些操作时需要使用矩阵运算。
你可以将矩阵想象成一个多维数组。比如,在3D空间中我们使用一个像下面这种格式的4X4矩阵:

[X][0][0][0][0][Y][0][0][0][0][Z][0][0][0][0][1]

把这个矩阵和物体的每一个坐标点(又称顶点)相乘,我们可以得到物体的一个变换(transformation)效果。
严格点讲,前面这个矩阵是用来执行缩放操作的。其中的X、Y、Z值代表每个轴上的缩放值。
如果你要进行其他的变换操作,比如旋转或者平移,你需要将矩阵换成其他矩阵格式(scheme)。

不要紧张!你不需要知道其他更多原理知识,而且也不必直接进行这些操作。Core Animation会为你完成这些操作,虽然你不知道它是如何做到的,但是它确实会为你完成这些操作,所以不必害怕。
当然,就我个人来说,如果我知道它背后是如何工作的(至少知道一些它的基本原理),我会对我的代码更有自信。因此,如果你想了解更多矩阵相关的知识,建议你读一读这篇文章

###3D变换(Transformations)
现在基本上,你已经知道矩阵的作用了,也知道了3D空间是如何构成的。来,我们用Core Animation做一些3D的东西吧。
打开TB_3DIntro->viewController.m文件。
我在里面列出了6个分别以A、B、C、D、E、F开头的函数。每一个函数对应了一种不同的3D场景效果。
我们先来看看由A_singlePlan函数创造的场景吧。
用这个函数,我们画了一个平面,平面绕Y轴旋转了45度。
首先,我们创建了一个CALayer,用它来作容器层(当然,并不是一定要这样做,只是我更喜欢不直接在self.view的layer上进行工作)。

-(void)A_singlePlane{//Create the containerCALayer*container=[CALayerlayer];container.frame=CGRectMake(0,0,640,300);[self.view.layeraddSublayer:container];

然后我们创建了另一个CALayer,用它代表一个平面。

//Create a PlaneCALayer*purplePlane=[selfaddPlaneToLayer:containersize:CGSizeMake(100,100)position:CGPointMake(250,150)color:[UIColorpurpleColor]];

我写了一个简单的辅助函数,用它将平面直接添加到容器层上,然后返回这个新建的平面层。代码非常简单:

-(CALayer*)addPlaneToLayer:(CALayer*)containersize:(CGSize)sizeposition:(CGPoint)pointcolor:(UIColor*)color{//Initialize the layerCALayer*plane=[CALayerlayer];//Define position,size and colorsplane.backgroundColor=[colorCGColor];plane.opacity=0.6;plane.frame=CGRectMake(0,0,size.width,size.height);plane.position=point;plane.anchorPoint=CGPointMake(0.5,0.5);plane.borderColor=[[UIColorcolorWithWhite:1.0alpha:0.5]CGColor];plane.borderWidth=3;plane.cornerRadius=10;//Add the layer to the container layer[containeraddSublayer:plane];returnplane;}

最后,我们用CATransform3D来添加变换。
啊???你一定又想问CATransform3D是什么东西?按住Cmd键点击这个类型名称,你可以发现它是一个结构体,使用了一种很”火星”的语法来表示一个矩阵。

structCATransform3D{CGFloatm11,m12,m13,m14;CGFloatm21,m22,m23,m24;CGFloatm31,m32,m33,m34;CGFloatm41,m42,m43,m44;};typedefstructCATransform3DCATransform3D;

旋转变换部分的代码也相当简单:

//Apply transform to the PLANECATransform3Dt=CATransform3DIdentity;t=CATransform3DRotate(t,45.00f*M_PI/180.0f,0,1,0);purplePlane.transform=t;}

先用单位矩阵CATransform3DIdentity来初始化一个变换(transformation),然后用CATransform3DRotate函数给变换乘上一个旋转矩阵。
CATransform3DRotate这个函数的参数分别表示矩阵,旋转的角度(以弧度为单位)和3个坐标轴上的变换系数。这个例子中,X和Z轴都没受到影响,只对Y轴有影响,物体会在Y轴上旋转45度。
下图是运行结果。

呃……你可以看到,它还不是3D的!我们只是在X轴方向上将一个正方形压扁了。
这是由于我们还没有设置视点的值(perspective value)。通常,在绘制3D场景的时候会将场景进行正射投影(Orthographic projection)处理,由此会产生一个扁平的场景。换句话说,在正射投影后你无法看到Z轴上的深度感。
要给我们的场景加上空间深度感,我们必须修改变换矩阵的m34参数。这个参数决定了视点的值。
现在,来看看B_singlePlanePerspective这个函数,这函数展示了视点的作用。
这个函数和前一个函数只有变换部分的代码有所不同:

//Apply transform to the PLANECATransform3Dt=CATransform3DIdentity;//Add perspective!!!t.m34=1.0/-500;t=CATransform3DRotate(t,degToRad(45.0),0,1,0);purplePlane.transform=t;}

你可以看到,我们直接给矩阵的m34属性赋了一个值。在这里,我不会深入的从数学上解释这个值是如何起作用的。但是我可以告诉你的是,这个值越接近0,视点就越深。
下面是两种不同视点值的效果:

###3D变换的顺序问题(Transformations chain)
我们可以将多个矩阵相乘从而将多种变换应用到一个物体上。比如,如果我们想将平移和旋转变换应用到一个物体上,我们可以直接将两个变换矩阵相乘:

TransformMatrix=TranslateMtx*RotateMtx

数学上,一般情况下乘法都可以使用交换律:

TranslateMtx*RotateMxt=RotateMtx*TranslateMtx

但是矩阵乘法不适用于交换律。AxB的结果可能和BxA的结果不一样。要记住这一点!
接下来C_transformationsChain这个例子中,我们会将2个变换效果按不同的先后顺序应用到2个不同的物体上。
以下是主要代码:

//Apply transformation to the PLANESCATransform3Dt=CATransform3DIdentity;//Purple plane: Perform a rotation and then a translationt=CATransform3DRotate(t,45.0f*M_PI/180.0f,0,0,1);t=CATransform3DTranslate(t,100,0,0);purplePlane.transform=t;//reset the transform matrixt=CATransform3DIdentity;//Red plane: Perform translation first and then the rotationt=CATransform3DTranslate(t,100,0,0);t=CATransform3DRotate(t,45.0f*M_PI/180.0f,0,0,1);redPlane.transform=t;

运行结果如下:

看到了吗,不同的变换顺序完全导致了不同的效果。
我们重点下看一下紫色的那块。旋转变换改变了它的坐标轴方向,然后我们又将它沿X轴进行了平移,此时它的X轴方向已经和红色平面的X轴方向不一致了。
变换步骤示意图如下:

###图层层次(layer hierarchies)
到目前为止,我们都是将变换直接应用在这些平面上。在3D场景中,经常需要创建一些相互之间有层次结构的物体。这个时候,只需要将变换应用到根层次上,就可以使整个层次结构中的物体整体具有这个变换效果。这种做法非常有用。
接下来,我们来看看D_multiplePlanes这个例子。
我们在容器层上添加了4个平面。
当没有任何变换效果时看起来是这样的:

如果我们给每一个平面都加上一个Y轴上的旋转变换,我们会得到4个独立的旋转效果:

但是,如果我们只是在容器层上应用旋转变换,我们会得到一个完全不同的场景效果:

这种效果,是相机(camera)位置发生改变带来的结果。我们没有移动每个平面,只是改变了视点的位置。
此函数主要的变换部分代码如下,包含了分别应用于各个平面和应用于容器层的两种变换效果的代码:

//Transformation CATransform3Dt=CATransform3DIdentity;BOOLapplyToContainer=NO;//Apply the transformation to each PLANEif(!applyToContainer){t.m34=1.0/-500.0;t=CATransform3DRotate(t,degToRad(60.0),0,1,0);purplePlane.transform=t;t=CATransform3DIdentity;t.m34=1.0/-500.0;t=CATransform3DRotate(t,degToRad(60.0),0,1,0);redPlane.transform=t;t=CATransform3DIdentity;t.m34=1.0/-500.0;t=CATransform3DRotate(t,degToRad(60.0),0,1,0);orangePlane.transform=t;t=CATransform3DIdentity;t.m34=1.0/-500.0;t=CATransform3DRotate(t,degToRad(60.0),0,1,0);yellowPlane.transform=t;}//Apply the transformation to the CONTAINERelse{CATransform3Dt=CATransform3DIdentity;t.m34=1.0/-500;t=CATransform3DRotate(t,degToRad(60.0),0,1,0);container.transform=t;}

###CATransformLayer
到目前为止我们所见到的代码都能正常工作,但说实话,作为3D层次结构的根,CALayer不是正确的选择。
函数E_multiplePlanesZAxis展示了为什么。
这个例子中,我们创建4个XY坐标相同只有Z坐标不同的平面。紫色平面最近,黄色平面最远。

//Apply transforms to the PLANESt=CATransform3DIdentity;t=CATransform3DTranslate(t,0,0,-10);purplePlane.transform=t;t=CATransform3DIdentity;t=CATransform3DTranslate(t,0,0,-50);redPlane.transform=t;t=CATransform3DIdentity;t=CATransform3DTranslate(t,0,0,-90);orangePlane.transform=t;t=CATransform3DIdentity;t=CATransform3DTranslate(t,0,0,-130);yellowPlane.transform=t;

在旋转这些平面前,我们先让容器层执行了一个旋转变换。

//Apply transform to the CONTAINERCATransform3Dt=CATransform3DIdentity;t.m34=1.0/-500;t=CATransform3DRotate(t,80.0f*M_PI/180.0f,0,1,0);container.transform=t;

你也许希望看到下面这种结果:

但是,实际上会得到这种结果:

这是因为CALayer不能处理3D层次结构的深度,它只能将场景处理成相同的Z层次。
为了修正这个问题,我们需要用一个CATransformLayers来做根层对象。
函数F_multiplePlanesZAxis修正了这个问题:

//Create the container as a CATransformLayerCATransformLayer*container=[CATransformLayerlayer];container.frame=CGRectMake(0,0,640,300);[self.view.layeraddSublayer:container];

CATransformLayer是一个特殊的layer。与CALayer的不同之处在于,CATransformLayer本身不会被渲染到屏幕上,只有它的子图层才会被渲染到屏幕上。所以它的一些属性,比如backgroundColor、contents、border等等都没有什么用。要记住这点。
到这里,这个教程的第一部分就完了。建议你实际运行一下这些函数,也可以试试我没有讲到的CATransform3DScale,试试用它做一个缩放变换看。
如果你有任何问题,可以在twitter上找到我(@bitwaker)。
本教程代码下载
译自:Think
& Build

|