zoukankan      html  css  js  c++  java
  • [iOS UI进阶

    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
    最简单最直接的方式:直接跳到拨号界面
    1 NSURL *url = [NSURL URLWithString:@"tel://10086"];
    2 [[UIApplication sharedApplication] openURL:url];
    缺点
    电话打完后,不会自动回到原应用,直接停留在通话记录界面
     
    b.方法2
    拨号之前会弹框询问用户是否拨号,拨完后能自动回到原应用
    1 NSURL *url = [NSURL URLWithString:@"telprompt://10086"];
    2 [[UIApplication sharedApplication] openURL:url];
    缺点
    因为是私有API,所以可能不会被审核通过
     
    c.方法3
    创建一个UIWebView来加载URL,拨完后能自动回到原应用
    1 if (_webView == nil) {
    2     _webView = [[UIWebView alloc] initWithFrame:CGRectZero];
    3 }
    4 [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"tel://10010"]]];
    需要注意的是:这个webView千万不要添加到界面上来,不然会挡住其他界面
     
    (2)发短信
    a.方法1
    直接跳到发短信界面,但是不能指定短信内容,而且不能自动回到原应用
    1 NSURL *url = [NSURL URLWithString:@"sms://10086"];
    2 [[UIApplication sharedApplication] openURL:url];
     
    b.方法2
    #mark:
    注意要写对代理名称messageComposeDelegate和mailComposeDelegate,不是delegate
     
    如果想指定短信内容,那就得使用MessageUI框架
    包含主头文件
    #import <MessageUI/MessageUI.h>

    显示发短信的控制器
     1 MFMessageComposeViewController *vc = [[MFMessageComposeViewController alloc] init];
     2 // 设置短信内容
     3 vc.body = @"吃饭了没?";
     4 // 设置收件人列表
     5 vc.recipients = @[@"10086", @"13800138000"];
     6 // 设置代理(这里使用block封装,由于强指针持有self,会有内存泄露)
     7 vc.messageComposeDelegate = self;
     8 
     9 // 显示控制器
    10 [self presentViewController:vc animated:YES completion:nil];
     
    代理方法,当短信界面关闭的时候调用,发完后会自动回到原应用
     1 - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
     2 {
     3     // 关闭短信界面
     4     [controller dismissViewControllerAnimated:YES completion:nil];
     5    
     6     if (result == MessageComposeResultCancelled) {
     7         NSLog(@"取消发送");
     8     } else if (result == MessageComposeResultSent) {
     9         NSLog(@"已经发出");
    10     } else {
    11         NSLog(@"发送失败");
    12     }
    13 }
     
    (3)发邮件
    a.方法1
    用自带的邮件客户端,发完邮件后不会自动回到原应用
    1 NSURL *url = [NSURL URLWithString:@"mailto://10010@qq.com"];
    2 [[UIApplication sharedApplication] openURL:url];
     
    b.方法2
    跟发短信的第2种方法差不多,只不过控制器类名叫做:MFMailComposeViewControlle
     1       // 方法2:使用控制器
     2         MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
     3        
     4         // 发送主题
     5         [mailController setSubject:@"重要作战会议"];
     6        
     7         // 邮件内容
     8         [mailController setMessageBody:@"就是那个...该吃饭了吧" isHTML:NO];
     9        
    10         // 收件人
    11         [mailController setToRecipients:@[@"hellovoidworld@163.com"]];
    12        
    13         // 抄送人
    14         [mailController setCcRecipients:@[@"hellovoidworld@163.com"]];
    15         
    16         // 密送人
    17          [mailController setBccRecipients:@[@"hellovoidworld@163.com"]];
    18         
    19         // 附件
    20         UIImage *image = [UIImage imageNamed:@"LoginScreen"];
    21         NSData *data = UIImagePNGRepresentation(image);
    22         [mailController addAttachmentData:data mimeType:@"image/png" fileName:@"attach.png"];
    23        
    24         // 代理
    25         mailController.mailComposeDelegate = shareController;
    26        
    27         // 弹出mail控制器
    28         [shareController presentViewController:mailController animated:YES completion:nil];
     
    邮件发送后的代理方法回调,发完后会自动回到原应用
     1 - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
     2 {
     3     // 关闭邮件界面
     4     [controller dismissViewControllerAnimated:YES completion:nil];
     5    
     6     if (result == MFMailComposeResultCancelled) {
     7         NSLog(@"取消发送");
     8     } else if (result == MFMailComposeResultSent) {
     9         NSLog(@"已经发出");
    10     } else {
    11         NSLog(@"发送失败");
    12     }
    13 }
     
    (4)打开其他常见文件
    如果想打开一些常见文件,比如html、txt、PDF、PPT等,都可以使用UIWebView打开
    只需要告诉UIWebView文件的URL即可
    至于打开一个远程的共享资源,比如http协议的,也可以调用系统自带的Safari浏览器:
    1 NSURL *url = [NSURL URLWithString:@”http://www.baidu.com"];
    2 [[UIApplication sharedApplication] openURL:url];
     
    (5)应用跳转
    有时候,需要在本应用中打开其他应用,比如从A应用中跳转到B应用
    首先,应用app得有自己的URL地址(在Info.plist中配置)
    例如:app应用的URL地址就是:hvw://com.ios.app
     
    接着在某个应用中使用UIApplication完成跳转
    1 NSURL *url = [NSURL URLWithString:@"hvw://com.ios.app"];
    2 [[UIApplication sharedApplication] openURL:url];
     
    (6)应用评分
    为了提高应用的用户体验,经常需要邀请用户对应用进行评分
    应用评分无非就是跳转到AppStore展示自己的应用,然后由用户自己撰写评论

    如何跳转到AppStore,并且展示自己的应用
    方法1
    1 NSString *appid = @"444934666";
    2 NSString *str = [NSString stringWithFormat:
    3                  @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%@", appid];
    4 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];

    方法2
    1 NSString *str = [NSString stringWithFormat:
    2                  @"itms-apps://itunes.apple.com/cn/app/id%@?mt=8", appid];
    3 [[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代码来调用系统软件
     
    Image
     
      1 //
      2 //  HVWShareViewController.m
      3 //  HelloLottery
      4 //
      5 //  Created by hellovoidworld on 15/1/9.
      6 //  Copyright (c) 2015年 hellovoidworld. All rights reserved.
      7 //
      8 
      9 #import "HVWShareViewController.h"
     10 #import "HVWArrowSettingItem.h"
     11 #import "HVWSettingGroup.h"
     12 #import <MessageUI/MessageUI.h>
     13 
     14 @interface HVWShareViewController () <MFMessageComposeViewControllerDelegate, MFMailComposeViewControllerDelegate>
     15 
     16 @end
     17 
     18 @implementation HVWShareViewController
     19 
     20 - (void)viewDidLoad {
     21     [super viewDidLoad];
     22     // Do any additional setup after loading the view.
     23    
     24     // 配置数据
     25     HVWSettingItem *weiboShare = [HVWArrowSettingItem itemWithIcon:@"WeiboSina" title:@"新浪微博分享"];
     26     HVWSettingItem *smsShare = [HVWArrowSettingItem itemWithIcon:@"SmsShare" title:@"短信分享"];
     27   
     28     // 为了避免block内持有本控制器,导致内存泄露,先声明一个弱指针
     29     __weak HVWShareViewController *shareController = self;
     30    
     31     smsShare.runningBlock = ^ {
     32         // 方法1:只能打开短信窗口,不能指定内容
     33         //        NSURL *smsURL = [NSURL URLWithString:@"sms://10086"];
     34         //        [[UIApplication sharedApplication] openURL:smsURL];
     35 
     36         // 方法2:
     37         //获取短信发送控制器
     38         if (![MFMessageComposeViewController canSendText]) return;
     39        
     40         MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
     41        
     42         // 短信内容
     43         messageController.body = @"吃饭了没有?";
     44        
     45         // 收件人
     46         messageController.recipients = @[@"10086"];
     47        
     48         // 设置代理,特别注意代理是messageComposeDelegate,不是delegate
     49         messageController.messageComposeDelegate = shareController;
     50        
     51         // 显示控制器
     52         [shareController presentViewController:messageController animated:YES completion:nil];
     53     };
     54    
     55     HVWSettingItem *mailShare = [HVWArrowSettingItem itemWithIcon:@"MailShare" title:@"邮件分享"];
     56     mailShare.runningBlock = ^ {
     57       // 方法1:直接调用
     58 //        NSURL *mailURL = [NSURL URLWithString:@"mailto://hellovoidworld@163.com"];
     59 //        [[UIApplication sharedApplication] openURL:mailURL];
     60 
     61       // 方法2:使用控制器
     62         MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
     63        
     64         // 发送主题
     65         [mailController setSubject:@"重要作战会议"];
     66        
     67         // 邮件内容
     68         [mailController setMessageBody:@"就是那个...该吃饭了吧" isHTML:NO];
     69        
     70         // 收件人
     71         [mailController setToRecipients:@[@"hellovoidworld@163.com"]];
     72        
     73         // 抄送人
     74         [mailController setCcRecipients:@[@"hellovoidworld@163.com"]];
     75         
     76         // 密送人
     77          [mailController setBccRecipients:@[@"hellovoidworld@163.com"]];
     78         
     79         // 附件
     80         UIImage *image = [UIImage imageNamed:@"LoginScreen"];
     81         NSData *data = UIImagePNGRepresentation(image);
     82         [mailController addAttachmentData:data mimeType:@"image/png" fileName:@"attach.png"];
     83        
     84         // 代理
     85         mailController.mailComposeDelegate = shareController;
     86        
     87         // 弹出mail控制器
     88         [shareController presentViewController:mailController animated:YES completion:nil];
     89        
     90     };
     91    
     92     HVWSettingGroup *group = [[HVWSettingGroup alloc] init];
     93     group.items = @[weiboShare, smsShare, mailShare];
     94     [self.data addObject:group];
     95 }
     96 
     97 - (void)didReceiveMemoryWarning {
     98     [super didReceiveMemoryWarning];
     99     // Dispose of any resources that can be recreated.
    100 }
    101 
    102 #pragma mark - MFMessageComposeViewControllerDelegate 代理方法
    103 /** 关闭信息后 */
    104 - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
    105     // 关闭信息窗口
    106     [controller dismissViewControllerAnimated:YES completion:nil];
    107    
    108     // 检测发送情况
    109     if (MessageComposeResultSent == result) {
    110         NSLog(@"成功发送!");
    111     } else if (MessageComposeResultFailed == result) {
    112         NSLog(@"发送失败!");
    113     } else if (MessageComposeResultCancelled == result) {
    114         NSLog(@"取消发送!");
    115     } else {
    116         NSLog(@"发生错误!");
    117     }
    118 }
    119 
    120 /** 关闭邮件后 */
    121 - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
    122     [controller dismissViewControllerAnimated:YES completion:nil];
    123 }
    124 
    125 @end
     
    2.“关于”模块
    使用self.tableView.headerView自定义组头部
     
    Image(1)
     
    (1)使用xib设计头部
    Image(2)
     
    (2)创建一个类“设置”界面控制器
    Image(3)
     
    应用评分
    其实就是打开AppStore中相应的软件
    协议头:itms-apps://
     
    打电话
    使用webView来打开URL
    协议头:tel://
     
     1 //
     2 //  HVWAboutViewController.m
     3 //  HelloLottery
     4 //
     5 //  Created by hellovoidworld on 15/1/8.
     6 //  Copyright (c) 2015年 hellovoidworld. All rights reserved.
     7 //
     8 
     9 #import "HVWAboutViewController.h"
    10 #import "HVWArrowSettingItem.h"
    11 #import "HVWSettingGroup.h"
    12 
    13 @interface HVWAboutViewController ()
    14 
    15 @end
    16 
    17 @implementation HVWAboutViewController
    18 
    19 - (void)viewDidLoad {
    20     [super viewDidLoad];
    21     // Do any additional setup after loading the view.
    22    
    23     // 准备一个webView
    24     UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
    25     [self.view addSubview:webView];
    26    
    27    
    28     // 配置item和group
    29     HVWSettingItem *gradeSupport = [HVWArrowSettingItem itemWithTitle:@"评分支持"];
    30    
    31     // 跳转到app store进行应用评分
    32     gradeSupport.runningBlock = ^ {
    33       // 其实这是网易新闻的app id
    34         NSString *appid = @"425349261";
    35         NSString *appStoreAddr = [NSString stringWithFormat:@"http://itunes.apple.com/app/id%@?mt=8", appid];
    36         NSURL *appStoreURL = [NSURL URLWithString:appStoreAddr];
    37         [[UIApplication sharedApplication] openURL:appStoreURL];
    38     };
    39    
    40     HVWSettingItem *servicePhone = [HVWArrowSettingItem itemWithTitle:@"客服电话"];
    41     NSString *phoneNumber = @"020-83568090";
    42     servicePhone.subTitle = phoneNumber;
    43    
    44     servicePhone.runningBlock = ^{
    45         NSURL *phoneURL = [NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",phoneNumber]];
    46         [webView loadRequest:[NSURLRequest requestWithURL:phoneURL]];
    47     };
    48 
    49     HVWSettingGroup *group = [[HVWSettingGroup alloc] init];
    50     group.items = @[gradeSupport, servicePhone];
    51     [self.data addObject:group];
    52    
    53     // header
    54     // 配置header view
    55     UINib *nib = [UINib nibWithNibName:@"HVWAboutHeader" bundle:[NSBundle mainBundle]];
    56     UIView *view = [[nib instantiateWithOwner:nil options:nil] lastObject];
    57     self.tableView.tableHeaderView  = view;
    58     self.tableView.tableHeaderView.frame = view.bounds;
    59 }
    60 
    61 - (void)didReceiveMemoryWarning {
    62     [super didReceiveMemoryWarning];
    63     // Dispose of any resources that can be recreated.
    64 }
    65 
    66 @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在开关改变值之后自动存储键值
    Image(4)
     
    HVWSettingCell:
     1 /** 创建“开关”类型的cell */
     2 - (UISwitch *)switchView {
     3     if (nil == _switchView) {
     4         _switchView = [[UISwitch alloc] init];
     5        
     6         // 监听开关
     7         [_switchView addTarget:self action:@selector(switchChange) forControlEvents:UIControlEventValueChanged];
     8     }
     9     return _switchView;
    10 }
    11  
    12 /** 开关变化事件 
    13 * 存储开关状态到preferences
    14 */
    15 - (void) switchChange {
    16     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    17     // 使用cell的title作为key,开关状态作为value
    18     [defaults setBool:self.switchView.isOn forKey:self.item.title];
    19     // 立即存储
    20     [defaults synchronize];
    21 }
    22 
    23 /** 读取开关状态 */
    24 - (BOOL) readSwitchStatus {
    25     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    26     return [defaults boolForKey:self.item.title];
    27 }
     
    4.打开其他应用
    Image(5)
     
    一样使用openURL
    (1)给要打开的app配置应用URL(可以配置多个)
    a.info.plist:添加URL types
    b.添加协议头(可以配置多个,也可以不配)
    c.添加identifier
    Image(6)
     
    (2)打开应用/打开AppStore下载应用
    所以应该配置两个URL:
    • 打开应用URL
    • 下载应用URL
     
    a.判断app是否已经安装
    UIApplication中的方法: - (BOOL) canOpenURL:(NSURL *) url
     
    这里使用素材带的json数据
    Image(7)
     
     
    HVWProductViewController
     1 #pragma mark <UICollectionViewDelegate>
     2 /** 选择事件 */
     3 - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
     4     HVWProduct *product = self.products[indexPath.item];
     5    
     6     NSURL *appUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", product.urlSchema, product.urlId]];
     7     NSURL *appStoreUrl = [NSURL URLWithString:product.appStoreUrl];
     8 
     9     UIApplication *application = [UIApplication sharedApplication];
    10     // 先判断是否存在此app
    11     if ([application canOpenURL:appUrl]) {
    12         // 打开app
    13         [application openURL:appUrl];
    14     } else {
    15         // 跳转到app store下载app
    16         [application openURL:appStoreUrl];
    17     }
    18 }
     
    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"修饰符
    注意:也不要使用强指针访问对象的属性
    Image(8)
     
     
    7.屏幕适配
    Autoresizing属性:能够设置控件在不同尺寸屏幕下的大小
    要先取消勾选Autolayout才能使用Autoresizing属性
    Image(9)
     
    四周的4条指示条:代表和边框的距离固定
    中间的2条指示条:代表宽高的自动适配
  • 相关阅读:
    Linux内核配置过程
    Linux内核最顶层文档
    LeetCode 11月第2周题目汇总
    Chapter0
    序列加法的讨论
    ch2-基本工具介绍
    ch1-数据科学概述
    在Linux下制作Linux&windows启动盘
    VMware Workstation 与 Device/Credential Guard 不兼容?
    Linux mint 19.3配置CUDA+安装Tensorflow
  • 原文地址:https://www.cnblogs.com/hellovoidworld/p/4214335.html
Copyright © 2011-2022 走看看