A.需求
  1. 真机调试
  2. "关于”模块
  3. 存储开关状态
  4. 打电话、发短信
  5. 应用评分
  6. 打开其他应用
  7. cell 在iOS6 和 iOS7的适配
  8. block的循环引用
  9. 屏幕适配
code source:  code source: https://github.com/hellovoidworld/HelloLottery
 
B.iOS真机测试小功能
(1)打电话
a.方法1
最简单最直接的方式:直接跳到拨号界面
 NSURL *url = [NSURL URLWithString:@"tel://10086"];
[[UIApplication sharedApplication] openURL:url];

缺点
电话打完后,不会自动回到原应用,直接停留在通话记录界面

 
b.方法2
拨号之前会弹框询问用户是否拨号,拨完后能自动回到原应用

 NSURL *url = [NSURL URLWithString:@"telprompt://10086"];
[[UIApplication sharedApplication] openURL:url];

缺点
因为是私有API,所以可能不会被审核通过

 
c.方法3
创建一个UIWebView来加载URL,拨完后能自动回到原应用

 if (_webView == nil) {
_webView = [[UIWebView alloc] initWithFrame:CGRectZero];
}
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"tel://10010"]]];

需要注意的是:这个webView千万不要添加到界面上来,不然会挡住其他界面

 
(2)发短信
a.方法1
直接跳到发短信界面,但是不能指定短信内容,而且不能自动回到原应用
 NSURL *url = [NSURL URLWithString:@"sms://10086"];
[[UIApplication sharedApplication] openURL:url];
 
b.方法2
#mark:
注意要写对代理名称messageComposeDelegate和mailComposeDelegate,不是delegate
 
如果想指定短信内容,那就得使用MessageUI框架
包含主头文件
#import <MessageUI/MessageUI.h>

显示发短信的控制器

 MFMessageComposeViewController *vc = [[MFMessageComposeViewController alloc] init];
// 设置短信内容
vc.body = @"吃饭了没?";
// 设置收件人列表
vc.recipients = @[@"", @""];
// 设置代理(这里使用block封装,由于强指针持有self,会有内存泄露)
vc.messageComposeDelegate = self; // 显示控制器
[self presentViewController:vc animated:YES completion:nil];
 
代理方法,当短信界面关闭的时候调用,发完后会自动回到原应用

 - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
// 关闭短信界面
[controller dismissViewControllerAnimated:YES completion:nil]; if (result == MessageComposeResultCancelled) {
NSLog(@"取消发送");
} else if (result == MessageComposeResultSent) {
NSLog(@"已经发出");
} else {
NSLog(@"发送失败");
}
}
 
(3)发邮件
a.方法1
用自带的邮件客户端,发完邮件后不会自动回到原应用

 NSURL *url = [NSURL URLWithString:@"mailto://10010@qq.com"];
[[UIApplication sharedApplication] openURL:url];
 
b.方法2
跟发短信的第2种方法差不多,只不过控制器类名叫做:MFMailComposeViewControlle
       // 方法2:使用控制器
MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init]; // 发送主题
[mailController setSubject:@"重要作战会议"]; // 邮件内容
[mailController setMessageBody:@"就是那个...该吃饭了吧" isHTML:NO]; // 收件人
[mailController setToRecipients:@[@"hellovoidworld@163.com"]]; // 抄送人
[mailController setCcRecipients:@[@"hellovoidworld@163.com"]]; // 密送人
[mailController setBccRecipients:@[@"hellovoidworld@163.com"]]; // 附件
UIImage *image = [UIImage imageNamed:@"LoginScreen"];
NSData *data = UIImagePNGRepresentation(image);
[mailController addAttachmentData:data mimeType:@"image/png" fileName:@"attach.png"]; // 代理
mailController.mailComposeDelegate = shareController; // 弹出mail控制器
[shareController presentViewController:mailController animated:YES completion:nil];
 
邮件发送后的代理方法回调,发完后会自动回到原应用

 - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
// 关闭邮件界面
[controller dismissViewControllerAnimated:YES completion:nil]; if (result == MFMailComposeResultCancelled) {
NSLog(@"取消发送");
} else if (result == MFMailComposeResultSent) {
NSLog(@"已经发出");
} else {
NSLog(@"发送失败");
}
}
 
(4)打开其他常见文件
如果想打开一些常见文件,比如html、txt、PDF、PPT等,都可以使用UIWebView打开
只需要告诉UIWebView文件的URL即可
至于打开一个远程的共享资源,比如http协议的,也可以调用系统自带的Safari浏览器:

 NSURL *url = [NSURL URLWithString:@”http://www.baidu.com"];
[[UIApplication sharedApplication] openURL:url];
 
(5)应用跳转
有时候,需要在本应用中打开其他应用,比如从A应用中跳转到B应用
首先,应用app得有自己的URL地址(在Info.plist中配置)
例如:app应用的URL地址就是:hvw://com.ios.app
 
接着在某个应用中使用UIApplication完成跳转
 NSURL *url = [NSURL URLWithString:@"hvw://com.ios.app"];
[[UIApplication sharedApplication] openURL:url];
 
(6)应用评分
为了提高应用的用户体验,经常需要邀请用户对应用进行评分
应用评分无非就是跳转到AppStore展示自己的应用,然后由用户自己撰写评论

如何跳转到AppStore,并且展示自己的应用
方法1

 NSString *appid = @"";
NSString *str = [NSString stringWithFormat:
@"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%@", appid];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];

方法2

 NSString *str = [NSString stringWithFormat:
@"itms-apps://itunes.apple.com/cn/app/id%@?mt=8", appid];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
 
(7)真机调试步骤
真机调试的主要步骤
登录开发者主页
生成cer证书:cer是一个跟电脑相关联的证书文件,让电脑具备真机调试的功能
添加App ID:调试哪些app?
注册真机设备:哪台设备需要做真机调试?
生成MobileProvision文件:结合2、3、4生成一个手机规定文件
导入cer、MobileProvision文件

最终会得到2个文件
Cer文件:让电脑具备真机调试的功能
MobileProvision文件:哪台设备、哪些app、哪台电脑需要做真机调试?

 
 
C.实现
1.真机调试 - 分享功能
  • 新浪微博分享
  • 短信分享
  • 邮件分享
必须要打开系统自带的软件来进行
使用block代码来调用系统软件
 
 
 //
// HVWShareViewController.m
// HelloLottery
//
// Created by hellovoidworld on 15/1/9.
// Copyright (c) 2015年 hellovoidworld. All rights reserved.
// #import "HVWShareViewController.h"
#import "HVWArrowSettingItem.h"
#import "HVWSettingGroup.h"
#import <MessageUI/MessageUI.h> @interface HVWShareViewController () <MFMessageComposeViewControllerDelegate, MFMailComposeViewControllerDelegate> @end @implementation HVWShareViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view. // 配置数据
HVWSettingItem *weiboShare = [HVWArrowSettingItem itemWithIcon:@"WeiboSina" title:@"新浪微博分享"];
HVWSettingItem *smsShare = [HVWArrowSettingItem itemWithIcon:@"SmsShare" title:@"短信分享"]; // 为了避免block内持有本控制器,导致内存泄露,先声明一个弱指针
__weak HVWShareViewController *shareController = self; smsShare.runningBlock = ^ {
// 方法1:只能打开短信窗口,不能指定内容
// NSURL *smsURL = [NSURL URLWithString:@"sms://10086"];
// [[UIApplication sharedApplication] openURL:smsURL]; // 方法2:
//获取短信发送控制器
if (![MFMessageComposeViewController canSendText]) return; MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init]; // 短信内容
messageController.body = @"吃饭了没有?"; // 收件人
messageController.recipients = @[@""]; // 设置代理,特别注意代理是messageComposeDelegate,不是delegate
messageController.messageComposeDelegate = shareController; // 显示控制器
[shareController presentViewController:messageController animated:YES completion:nil];
}; HVWSettingItem *mailShare = [HVWArrowSettingItem itemWithIcon:@"MailShare" title:@"邮件分享"];
mailShare.runningBlock = ^ {
// 方法1:直接调用
// NSURL *mailURL = [NSURL URLWithString:@"mailto://hellovoidworld@163.com"];
// [[UIApplication sharedApplication] openURL:mailURL]; // 方法2:使用控制器
MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init]; // 发送主题
[mailController setSubject:@"重要作战会议"]; // 邮件内容
[mailController setMessageBody:@"就是那个...该吃饭了吧" isHTML:NO]; // 收件人
[mailController setToRecipients:@[@"hellovoidworld@163.com"]]; // 抄送人
[mailController setCcRecipients:@[@"hellovoidworld@163.com"]]; // 密送人
[mailController setBccRecipients:@[@"hellovoidworld@163.com"]]; // 附件
UIImage *image = [UIImage imageNamed:@"LoginScreen"];
NSData *data = UIImagePNGRepresentation(image);
[mailController addAttachmentData:data mimeType:@"image/png" fileName:@"attach.png"]; // 代理
mailController.mailComposeDelegate = shareController; // 弹出mail控制器
[shareController presentViewController:mailController animated:YES completion:nil]; }; HVWSettingGroup *group = [[HVWSettingGroup alloc] init];
group.items = @[weiboShare, smsShare, mailShare];
[self.data addObject:group];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} #pragma mark - MFMessageComposeViewControllerDelegate 代理方法
/** 关闭信息后 */
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
// 关闭信息窗口
[controller dismissViewControllerAnimated:YES completion:nil]; // 检测发送情况
if (MessageComposeResultSent == result) {
NSLog(@"成功发送!");
} else if (MessageComposeResultFailed == result) {
NSLog(@"发送失败!");
} else if (MessageComposeResultCancelled == result) {
NSLog(@"取消发送!");
} else {
NSLog(@"发生错误!");
}
} /** 关闭邮件后 */
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[controller dismissViewControllerAnimated:YES completion:nil];
} @end
 
2.“关于”模块
使用self.tableView.headerView自定义组头部
 
 
(1)使用xib设计头部
 
(2)创建一个类“设置”界面控制器
 
应用评分
其实就是打开AppStore中相应的软件
协议头:itms-apps://
 
打电话
使用webView来打开URL
协议头:tel://
 
 //
// HVWAboutViewController.m
// HelloLottery
//
// Created by hellovoidworld on 15/1/8.
// Copyright (c) 2015年 hellovoidworld. All rights reserved.
// #import "HVWAboutViewController.h"
#import "HVWArrowSettingItem.h"
#import "HVWSettingGroup.h" @interface HVWAboutViewController () @end @implementation HVWAboutViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view. // 准备一个webView
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
[self.view addSubview:webView]; // 配置item和group
HVWSettingItem *gradeSupport = [HVWArrowSettingItem itemWithTitle:@"评分支持"]; // 跳转到app store进行应用评分
gradeSupport.runningBlock = ^ {
// 其实这是网易新闻的app id
NSString *appid = @"";
NSString *appStoreAddr = [NSString stringWithFormat:@"http://itunes.apple.com/app/id%@?mt=8", appid];
NSURL *appStoreURL = [NSURL URLWithString:appStoreAddr];
[[UIApplication sharedApplication] openURL:appStoreURL];
}; HVWSettingItem *servicePhone = [HVWArrowSettingItem itemWithTitle:@"客服电话"];
NSString *phoneNumber = @"020-83568090";
servicePhone.subTitle = phoneNumber; servicePhone.runningBlock = ^{
NSURL *phoneURL = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",phoneNumber]];
[webView loadRequest:[NSURLRequest requestWithURL:phoneURL]];
}; HVWSettingGroup *group = [[HVWSettingGroup alloc] init];
group.items = @[gradeSupport, servicePhone];
[self.data addObject:group]; // header
// 配置header view
UINib *nib = [UINib nibWithNibName:@"HVWAboutHeader" bundle:[NSBundle mainBundle]];
UIView *view = [[nib instantiateWithOwner:nil options:nil] lastObject];
self.tableView.tableHeaderView = view;
self.tableView.tableHeaderView.frame = view.bounds;
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end
 
#mark:
1.不要使用autolayout,不然header显示不正确
2.不能使用代理方法 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
发现这样设置的头部是从section==1才开始的
 
 
3.存储开关状态
(1)监听开关
(2)及时存储
(3)初始化读取数据
使用preferences存储,key是cell的title,value就是bool值
监听所有的“开关”类型cell,让“开关”类型的cell在开关改变值之后自动存储键值
 
HVWSettingCell:
 /** 创建“开关”类型的cell */
- (UISwitch *)switchView {
if (nil == _switchView) {
_switchView = [[UISwitch alloc] init]; // 监听开关
[_switchView addTarget:self action:@selector(switchChange) forControlEvents:UIControlEventValueChanged];
}
return _switchView;
} /** 开关变化事件
* 存储开关状态到preferences
*/
- (void) switchChange {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 使用cell的title作为key,开关状态作为value
[defaults setBool:self.switchView.isOn forKey:self.item.title];
// 立即存储
[defaults synchronize];
} /** 读取开关状态 */
- (BOOL) readSwitchStatus {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults boolForKey:self.item.title];
}
 
4.打开其他应用

 
一样使用openURL
(1)给要打开的app配置应用URL(可以配置多个)
a.info.plist:添加URL types
b.添加协议头(可以配置多个,也可以不配)
c.添加identifier
 
(2)打开应用/打开AppStore下载应用
所以应该配置两个URL:
  • 打开应用URL
  • 下载应用URL
 
a.判断app是否已经安装
UIApplication中的方法: - (BOOL) canOpenURL:(NSURL *) url
 
这里使用素材带的json数据
 
 
HVWProductViewController
 #pragma mark <UICollectionViewDelegate>
/** 选择事件 */
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
HVWProduct *product = self.products[indexPath.item]; NSURL *appUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", product.urlSchema, product.urlId]];
NSURL *appStoreUrl = [NSURL URLWithString:product.appStoreUrl]; UIApplication *application = [UIApplication sharedApplication];
// 先判断是否存在此app
if ([application canOpenURL:appUrl]) {
// 打开app
[application openURL:appUrl];
} else {
// 跳转到app store下载app
[application openURL:appStoreUrl];
}
}
 
5.cell的 iOS6 & iOS7的适配(这里是针对iOS6适配成iOS7的样式)
由于cell在iOS6和iOS7上cell的显示不一样,所以需要进行统一适配
a.tableView使用统一的自定义背景
使用自带小图进行平铺操作合成背景
<1>清空backgroundView(避免在group样式下屏蔽了backgroundColor)
<2>使用平铺设置backgroundColor
 
b.cell使用统一的背景
c.cell使用统一的选中背景
<1>重写初始化方法initWithStyle
<2>设置选中时背景,选中状态适当调整颜色
 
d.统一cell内子控件样式
<1>清除子控件背景颜色
 
e.调整cell宽度,消除两边空隙
  • 重写cell的setFrame方法
  • 在iOS6及以下系统修改cell的位置尺寸,适配iOS7
 
f.加上cell之间的分隔线
  • iOS6中,cell中右部分的子控件不属于contentView,所以contentView的宽度是不定的
  • 每组的最后一行不需要分隔线
 
#mark:系统升级OSX10.10还有Xcode6之后,苹果似乎已经完全舍弃了iOS6,即使使用Xcode5下载了iOS6模拟器,打开后就是黑屏一片,不能使用。
 
 
6.block内的循环引用导致内存泄露
在block代码内,使用了强指针指向block所在的对象(例如self),导致循环引用,不能释放资源
将block内的对象引用设置为弱指针:使用"__weak"修饰符
注意:也不要使用强指针访问对象的属性
 
 
7.屏幕适配
Autoresizing属性:能够设置控件在不同尺寸屏幕下的大小
要先取消勾选Autolayout才能使用Autoresizing属性
 
四周的4条指示条:代表和边框的距离固定
中间的2条指示条:代表宽高的自动适配

[iOS UI进阶 - 2.3] 彩票Demo v1.3的更多相关文章

  1. [iOS UI进阶 - 2.4] 彩票Demo v1.4 转盘动画

    A.需求 幸运广场界面中有一个幸运转盘,平时能够自动缓缓转动 能够选择星座 点击“开始选号”开速旋转转盘,旋转一定周数 转盘转动速度节奏:开始-慢-块-慢-结束 设置其余的背景和按钮   code s ...

  2. [iOS UI进阶 - 2.0] 彩票Demo v1.0

    A.需求 1.模仿“网易彩票”做出有5个导航页面和相应功能的Demo 2.v1.0 版本搭建基本框架   code source:https://github.com/hellovoidworld/H ...

  3. [iOS UI进阶 - 2.1] 彩票Demo v1.1

    A.需求 1.优化项目设置 2.自定义导航栏标题按钮 3.多版本处理 4.iOS6和iOS7的适配 5.设置按钮背景 6.设置值UIBarButtonItem样式   code source: htt ...

  4. [iOS UI进阶 - 2.2] 彩票Demo v1.2 UICollectionView基本

    A.需要掌握的 设计.实现设置界面 cell的封装 UICollectionView的使用 自定义UICollectionView 抽取控制器父类 "帮助"功能 code sour ...

  5. [iOS UI进阶 - 5.0] 手势解锁Demo

    A.需求 1.九宫格手势解锁 2.使用了绘图和手势事件   code source: https://github.com/hellovoidworld/GestureUnlockDemo     B ...

  6. [iOS UI进阶 - 4.0] 涂鸦app Demo

    A.需求 1.超简易画图,只有一种画笔 2.清屏功能 3.回退功能 4.保存功能 5.使用了cocos2D   code source: https://github.com/hellovoidwor ...

  7. [iOS UI进阶 - 0] Quiartz2D

    A.简介 1. 需要掌握的 drawRect:方法的使用 常见图形的绘制:线条.多边形.圆 绘图状态的设置:文字颜色.线宽等 图形上下文状态的保存与恢复 图形上下文栈 1.基本图形绘制* 线段(线宽. ...

  8. iOS UI进阶-1.0 Quartz2D

    概述 Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统.Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成PDF ...

  9. UI进阶之--网易彩票手写plist文件,动态创建控制器与tableViewcell

    点击右上角设置按钮 点击按钮后发生的事件:1. 控制器的跳转,进入新的控制器.view, 2. 跳转的时候对将要跳转的目标控制的子控件进行了布局.---通过手写plist文件的方式加载 为按钮注册单击 ...

随机推荐

  1. Codeforces Round #205 (Div. 2)

    A #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> ...

  2. bundle update: env: ruby_executable_hooks: No such file or directory

    please open a bug here: https://github.com/mpapis/executable-hooks/issues as a temporary fix try: rv ...

  3. JPA中的@MappedSuperclass

    说明地址:http://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html 用来申明一个超类,继承这个类的子类映射 ...

  4. Firefox和Chrome浏览器导出书签

    Chrome浏览器: 或者直接在地址栏中输入:“chrome://bookmarks/#1”也可以 Firefox浏览器:

  5. UVa 10294 (Pólya计数) Arif in Dhaka (First Love Part 2)

    Burnside定理:若一个着色方案s经过置换f后不变,称s为f的不动点,将置换f的不动点的数目记作C(f).等价类的数目等于所有C(f)的平均值. 一个项链,一个手镯,区别在于一个能翻转一个不能,用 ...

  6. Html5大文件断点续传

    大文件分块   一般常用的web服务器都有对向服务器端提交数据有大小限制.超过一定大小文件服务器端将返回拒绝信息.当然,web服务器都提供了配置文件可能修改限制的大小.针对iis实现大文件的上传网上也 ...

  7. C# 编写的串口通信程序

    如果,翻看我之前的博客,会找到一篇用I/O模拟IIC通信的程序文章.好吧,如果找不到可以点击这里,这里就不在赘述了,系统也已经完全调试通过了. 今天的任务是,把测试得到的数据在上位机的界面上显示出来, ...

  8. [Sciter系列] MFC下的Sciter–1.创建工程框架

    Sciter SDK中提供的Win32下例程很多,唯独使用很多(对我个人而言)的MFC框架下Sciter程序的构建讲的很少,虽然MFC有这样那样的诟病,但是不可否认的是编写一般的小项目,这仍然是大多数 ...

  9. 【linux】命令

    pwd 显示路径 whereis jupyterhub find / -name base.py reboot 重启 grep

  10. Mybatis学习——基本增删改查(CRUD)

    Eclipse+Mybatis+MySql 1.所需jar 2.项目目录 3.源代码 package com.zhengbin.entity; public class Student { priva ...