zoukankan      html  css  js  c++  java
  • iOS基础-UIKit框架-多控制器管理-实例:私人通讯录

    一、搭建UI界面(一共4个界面,5个控制器),新建4个控制器文件


    二、各种功能的实现
    1.功能实现1:当账号密码被输入时,登录按钮激活
    1>连线监听2个文本框和登录按钮(Outlet)
    注意:addTarget:方法一般是监听点击事件,文字的改变是无法监听的。
    监听有三种方法,addTarget:方法,代理,通知。因为前2个在这里行不通,所以下面我们用通知来做。
    细节:文本框的Clear Button属性设置为Appears while editing,方便用户删除。
    2>通过通知来监听文本框文字的改变

    -(void)viewDidLoad

    {

        [super viewDidLoad];

        //监听通知

        [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(textChange) name:UITextFieldTextDidChangeNotification

    object:self.accountField];

        [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(textChange) name:UITextFieldTextDidChangeNotification

    object:self.pwdField];

    }

    //移除通知监听

    -(void)dealloc

    {

        [[NSNotificationCenter defaultCenter] removeObserver:self];

    }

    //文本框的文字发生改变的时候调用

    -(void)textChange

    {

        //控制按钮的状态

        self.loginBtn.enabled = (self.accountField.text.length && self.pwdField.text.length);

    }

    2.功能实现2:当取消记住密码时,自动登录也自动取消;当开启自动登录时,记住密码自动开启。
    1>连线监听2个开关(2个Outlet,2个Action)
    2>实现方法

    /**

     *  监听记住密码开关的值改变

     */

    - (IBAction)rmbPwdChange

    {

        if (self.rebPwdSwitch.isOn == NO){

            [self.autoLoginSwitch setOn:NO animated:YES];

      }

    }

    /**

     *  监听自动登录开关的值改变

     */

    - (IBAction)autoLoginChange

    {

        if (self.autoLoginSwitch.isOn){

            [self.rebPwdSwitch setOn:NO animated:YES];

      }

    }



    3.功能实现:注销的时候提醒用户:"确定要注销?"

    1>连线监听注销按钮(Action)并实现方法

    -(IBAction)logout:{
    

        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"确定要注销?" message:nil preferredStyle:UIAlertControllerStyleActionSheet];

    
    
    
    

        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];

    
    

        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {

    
    

            [self.navigationController popViewControllerAnimated:YES];

    
    

        }];

    
    

        [alertController addAction:cancelAction];

    
    

        [alertController addAction:okAction];

    
    

        [self presentViewController:alertController animated:YES completion:nil];

    }

    4.功能实现:点击登录按钮的时候先判断账号密码是否正确
    1>连线监听登录按钮(Action)并实现方法

    -(IBAction)login

    {

        if(![self.accountField.text isEqualToString:@"mj"]) {

            // 账号不存在

            [MBProgressHUD showError:@"账号不存在"];

            return;

        }

        

        if(![self.pwdField.text isEqualToString:@"123"]) {

            // 账号不存在

            [MBProgressHUD showError:@"密码错误"];

            return;

        }

        //显示一个蒙版(遮盖)

        [MBProgressHUD showMessage:@"正在登录中……"];

        

        //模拟(2秒后执行跳转)

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

            // 移除遮盖

            

            //跳转 -- 执行login2contacts遮盖segue

            [self performSegueWithIdentifier:@"login2contacts" sender:nil];

        });

    }

    5.功能实现:登录成功后,联系人列表显示为"XXX的联系人列表"(数据顺传)
    1>执行登录界面到联系人列表界面的segue时拿到联系人列表控制器。

    //(无论自动还是手动)执行segue后,跳转之前会自动调用这个方法(此方法属于来源控制器) 
    //一般在这里给下一个控制器传递数据

    -(void)prepareForSegue:(UIStoryboardSegue *)segue  sender:(id)sender

    {

        //1.取得目标控制器(联系人列表控制器)

        UIViewController *contactVc = segue.destinationViewController;

        //2.设置标题(contactVc.title == contactVc.navigationItem.title)

        contactVc.title = [NSString stringWithFormat:@"%@的联系人列表",self.accountField.text];

    }

    6.功能实现:只有在姓名和电话都输入的情况下添加按钮才能点击
    1>连线监听添加按钮(outlet)和2个文本框(outlet)
    2>通过通知来监听文本框文字的改变

    -(void)viewDidLoad
    {
          [super viewDidLoad];
    //监听通知
    [NSNotificationCenter defaultCenter] addObserver:self selector: @selector(textChange) name:UITextFieldTextDidChangeNotification 
    object:self.nameField];
    [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange)name:UITextFieldTextDidChangeNotification   
    object:self.phoneField];
    
    }
    
    //控制器view完全显示的时候调用
    -(void)viewDidAppear:(BOOL)animated
    {
         //当点击+号时,默认弹出键盘供用户输入(让姓名文本框成为第一响应者)
         [self.nameField bocomeFirstResponder];
    }
    -(void)dealloc
    
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    //文本框的文字发生改变的时候调用
    
    -(void)textChange
    
    {
        //控制按钮的状态
        self.addBtn.enabled = (self.nameField.text.length && self.phoneField.text.length); 
    }

    7.功能实现:点击添加按钮后回到上一个界面,并将姓名和电话传递到联系人列表界面(数据逆传)
    思路:用代理(当一个对象发生一些事情可以告诉代理),在这里就是添加联系人控制器添加成功后要告诉联系人列表控制器,列表得知其添加成功后,将数据拿过 
    来显示。完毕。(列表是代理,代理永远是接收数据的)
    1>连线监听添加按钮(Action)
    2>在“添加控制器”中新建一个代理协议并遵守

    @class MJAddViewController;
    @protocol MJAddViewControllerDelegate<NSObject>
    
    @optional
    -(void)addViewControllerDidAddContact:(MJAddViewController *)addVc didAddContact:(MJContect *)contact; 
    @end
    @property (nonatomic,weak) 
    id<MJAddViewControllerDelegate>delegate//id类型,所以谁都可以当代理,只要你想接收我的数据,你就当我的代理,这样就没有耦合性了。

    3>在添加控制器中实现添加按钮的方法

    -(IBAction)add
    {
    //1.关闭当前控制器
    [self.navigationController popViewControllerAnimated:YES];
    //2.通知代理(如果实现了代理方法,就给代理发送消息,通知代理,已经添加)
    if([self.delegate respondsToSelector:@selector(addViewController:didAddContact:)] ){ 
    MJContact *contact = [[MJContact alloc] init];
    contact.name = self.nameField.text;
    contact.phone = self.phoneField.text;
    [self.delegate addViewController:self didAddContact:self];
    }
    
    4>在联系人列表控制器中遵守代理协议,并重写prepareForSegue:方法(将添加的代理设为列表)
    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    {
       MJAddViewController *addVc = segue.destinationViewController;
       addVc.delegate =self;
    }

    5>实现数据源方法和代理方法
    #pragma mark 数据源方法
    第二个数据源方法:return self.contacts.count;
    第三个数据源方法:

    //1.创建cell
    static NSString *ID = @"contact";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID] ;
    }
    
    //2.设置cell的数据
    MJContact *cantact = self.contacts[IndexPath.row];
    cell.textLabel.text = contact.name;
    cell.detailTextLabel.text = contact.phone;
    
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    
    return cell;
    }
    #pragma mark - 代理方法
    -(void)addViewController:(MJaddViewController *)addVc didAddContact:(MJContect *)contact 
    {
    //1.添加模型数据
    [self.contacts addObject:contact];
    //2.刷新表格
    [self.tableView reloadData];
    }

    过程:

    1.点击+号-->系统自动调用prepareForSegue:方法(在这里设置目标控制器和代理)

    2.点击添加按钮-->来到add方法,关闭添加联系人界面,调用代理方法通知代理已经添加了联系人,并将数据传给代理

    3.来到代理方法,将传进来的数据添加到数组中并刷新表格。
    4.刷新表格后会重新调用数据源方法,取出数组中的模型,并将模型的属性赋值给cell的子控件。


    注意:要在C的viewDidLoad方法中取得数据,来赋值给界面上的UI控件

    8.功能实现:点击某一行cell来到查看/编辑联系人界面
    1>点击Cell,绑定重用标识contact
    2>按住ctrl将cell连到查看联系人控制器,选择push
    3>注意刚刚连接的线"目标控制器"是"添加联系人控制器",而这一条线"目标控制器"是"查看/编辑联系人控制器",所以需要在prepareForSegue:方法里进行判断

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    {
    id vc = segue.destinationViewController;
    if([vc isKindOfClass:[MJAddViewController class] ]){ //添加联系人
    MJAddViewController *addVc = vc;
    addVc.delegate =self;
    } else if ([vc isKindOfClass:[MJEditViewController class]]){ //查看/编辑
    //拿到目标控制器
    MJEditViewController *editVc = vc;
    //给编辑传递数据(需要在编辑里添加一个模型属性)
    //取得选中的那行
    NSIndexPath *path [self.tableView indexPathForSelectedRow];
    editVc.contact = self.contacts[path.row];
       }
    }

    4>查看联系人界面中保存按钮勾上Enabled和Hidden。姓名和电话去掉Enabled 。cell样式改为Right Detail

    9.功能实现:将联系人列表中的数据显示在查看联系人界面
    1>连线监听查看联系人界面的2个文本框(outlet)
    2>在查看联系人控制器的viewDidLoad中设置数据

    self.nameField.text = self.contact.name;
    self.phoneField.text = self.contact.phone;

    10.功能实现:点击查看联系人界面的编辑按钮进入编辑状态,并且弹出键盘
    1>连线监听查看联系人界面的保存按钮(Outlet)和编辑按钮(Action)并实现方法

    -(IBAction)edit:(UIBarButtonItem *)item
    {
     if(self.nameField.enabled){ //点击的是"取消"
     self.nameField.enabled = NO;
     self.phoneField.enabled = NO;
     [self.view endEditing:YES];
     self.saveBtn.hidden = YES;
     item.title = @"编辑"//还原回原来的数据
     self.nameField.text = self.contact.name;
     self.phoneField.text = self.contact.phone;
     } else { //点击的是"编辑"
                self.nameField.enabled = YES;
                self.phoneField.enabled = YES;
               [self.phoneField bocomeFirstResponder];
               self.saveBtn.hidden = NO;
               item.title = @"取消";
         } 
    }

    11.功能实现:只有查看联系人界面中的电话和姓名同时有值时保存键才激活
    1>在编辑联系人控制器的viewDidLoad中监听通知

    -(void)viewDidLoad
    
    {
    
      [super viewDidLoad]
    [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange)name:UITextFieldTextDidChangeNotification   
    object:self.accountField];
    [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange)name:UITextFieldTextDidChangeNotification   
    object:self.pwdField];
    }
    -(void)dealloc
    {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    -(void)textChange
    {
    self.addBtn.enabled = (self.nameField.text.length && self.phoneField.text.length); 
    }

    12.功能实现:点击查看联系人界面的保存后返回到联系人列表并更新数据
    1>在目标控制器创建一个代理协议并遵守
    2>连线监听保存按钮(Action)并实现方法

    -(IBAction)save
    
    {
    //1.关闭当前控制器View
    //2.通知代理已经保存
    if([self.delegate respondsToSelector:@selector(editViewController:didSaveContact:)] ){ 
    //更新模型数据
    self.contact.name = self.nameField.text;
    self.contact.phone = self.phoneField.text;
    [self.delegate editViewController:self didSaveContact:self.contact];
    }

    3>在代理中遵守协议,并在prepareForSegue:中将列表设为代理
    4>实现代理方法(在代理方法中调用reloadData即可)

    13.功能实现:当有数据时,cell才有分隔线。没有数据就没有分隔线。
    1>在联系人列表控制器的viewDidLoad中将所有线隐藏

    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

    2>手动添加分隔线(高度为1的UIView)
    1# 新建一个类用来封装cell,将storyboard里的cell的Class设置为这个自定义cell。并将数据源方法中cell 的创建改为创建这个自定义cell的类型。(而非系统自带), 而且不需要再设置cell右边的箭头了。
    2#在cell控制器中添加模型数据属性并提供一个静态方法快速创建cell(在这个方法中根据标识返回cell)
    3#将模型数据封装起来

    //1.创建cell
    UIContactCell *cell = [MJContactCell cellWithTableView:tableView];
    
    //2.设置cell的数据
    cell.contact = self.contacts[IndexPath.row];
    return cell;
    4#重写set方法,在其中设置数据
    cell.textLabel.text = contact.name;
    cell.detailTextLabel.text = contact.phone;

    PS:如果cell是通过storyboard或xib创建的,就不可能会调用initWithStyle来初始化cell

    5#在awakeFromNib里添加分隔线

    //如果cell是通过storyboard或xib创建的,就会调用下述方法
    -(void)awakeFromNib
    {
    UIView *divider = [UIView alloc] init];
    divider.backgroundColor = [UIColor blackColor];
    divider.alpha = 0.2;
    [self.contactView addSubview:divider];
    }

    6#在ContactCell中添加一条分隔线属性,并在awakeFromNib中给属性赋值

    7#在layoutSubviews方法中设置frame

     //在这里拿到的cell高度是准确的
    -(void)layoutSubviews     
    {
    [super layoutSubviews];
    CGFloat dividerX = 0;
    CGFloat dividerH = 1;
    CGFloat dividerY = self.frame.size.height - dividerH;
    CGFloat dividerW = self.frame.size.width;
    self.divider.frame = CGRectMake(dividerX ,dividerY ,dividerH ,dividerW ); 
    }

    14.功能实现:cell滑动删除

    #pragma mark - tableView的代理方法
    //如果实现了这个方法,就自动实现了滑动删除的功能
    //提交了一个编辑操作就会调用(操作:删除/添加)
    -(void)tableView:(UITableView)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    {
    if(editingStyle == UITableViewCellEditingStyleDelete){ //提交删除操作
    //1.删除模型数据
    [self.contacts removeObjectAtIndex:indexPath.row];
    //2.刷新表格
    [self.tableView deleteRowsAtIndexPaths:@:[indexPath] withRowAnimation:UITableViewRowAnimationTop];
    //3.归档
    [NSKeyedArchiver archiveRootObject:self.contacts toFile:MJContactsFilepath];
       }
    }

    知识补充:tableView的刷新
    1.数据刷新的总体步骤
    1>修改模型数据
    2>刷新表格(刷新界面)
    2.刷新表格的三种方法
    1>reloadData:整体刷新(每一行都会刷新)
    2>reloadRowsAtIndexPaths: 局部刷新(前提:刷新前后模型数据的个数不变)
    3>deleteRowsAtIndexPaths:局部删除(前提:模型数据减少个数=indexPaths的长度)

    15.功能实现:批量删除
    1>在viewDidLoad中拿到+号按钮,将其扔进数组,在数组中再添加一个垃圾桶

    -(void)viewDidLoad
    {
      [super viewDidLoad];
      UIBarButtonItem *addItem = self.navigationItem.rightBarButtonItem;
      UIBarButtonItem *deleteItem = [[UIBarButtonItem alloc]  initWithBarButtonSystemItem:UIBarButtonSystemItemTrash  target:self action:@selector(deleteClick)];
      self.navigationItem.rightBarButtonItems = @[deleteItem,addItem];
    }
    
    -(void)deleteClick
    {
    //让tableView进入编辑状态
    [self.tableView setEditing:!self.tableView.isEditing animated:YES];
    }

    知识补充:UITableViewController

  • 相关阅读:
    C#读取Excel设置(亲测可用)
    vue element-ui的对话框dialog没有height怎么解决?
    sqlserver不同服务器的不同数据库如何复制
    es6-对象与数组的解构赋值
    win10电脑上不了网了
    sqlserver数据库备份之后再还原
    “相对路径”以及“绝对路径”使用之坑
    sqlserver表-添加大量测试数据
    vue文件命名规范
    Git大小写问题
  • 原文地址:https://www.cnblogs.com/marshall-yin/p/4736817.html
Copyright © 2011-2022 走看看