zoukankan      html  css  js  c++  java
  • iOS UI基础04

    • 动画

      • 1.头尾式动画 动画开始
        [UIView beginAnimations:nil context:nil];
        设置动画时间
        [UIView s !           etAnimationDuration:3];
        [UIView setAnimationDelegate:self];
        只要写在开始和结束之间的代码, 就会被执行动画
        但是: 并不是所有的代码都能够执行动画
        只有属性声明中说明了是animatable的属性,才可以执行UIView动画
        CGRect tempFrame2 = self.hudLabel.frame;
        tempFrame2.origin.y -= 100;
        self.hudLabel.frame = tempFrame2;
        self.hudLabel.alpha = 1.0;
        self.hudLabel.hidden = YES;
        动画结束
        [UIView commitAnimations];
        
      • 2.block式动画 Duration: 动画执行的时长 animations: 在block中写需要执行动画的代码 completion: 动画结束后系统会自动调用该block delay: 延迟多少秒

        [UIView animateWithDuration:2 animations:^{
            self.hudLabel.alpha = 1.0;
        }];
        
        [UIView animateWithDuration:1.0 animations:^{
            self.hudLabel.alpha = 1.0;
        } completion:^(BOOL finished) {
            NSLog(@"动画结束了");
        
            [UIView animateWithDuration:1.0 delay:1.0 options:kNilOptions animations:^{
                self.hudLabel.alpha = 0.0;
            } completion:nil];
        
        }];
        
    • UIAlertController HUD(提示框)
      • 继承UIViewController
      • 注意:
        • 如果UIAlertController的样式是ActionSheet, 就不能添加输入框
          // 1.创建一个AlertController
          // Title : 按钮上显示的文字
          // style: 按钮的样式
          // handler: 点击按钮之后的回调
          UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@"标题" message:@"正文" preferredStyle:UIAlertControllerStyleActionSheet];
          UIAlertAction *action1 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * __nonnull action) {
          NSLog(@"点击了确定");
          }];
          UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * __nonnull action) {
          NSLog(@"点击了取消");
          }];
          [alertVc addAction:action1];
          [alertVc addAction:action2];
          // 2.显示
          [self presentViewController:alertVc animated:YES completion:nil];
          
          • 如果UIAlertController的样式是UIAlertControllerStyleAlert 就可以添加输入框
            // 添加一个输入框
            [alertVc addTextFieldWithConfigurationHandler:^(UITextField * __nonnull textField) {
            textField.text = @"用户名";
            NSLog(@"textField");
            }];
            
    • UIActionSheet

       // 1.创建UIActionSheet
        UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"哥是标题" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:@"其它", @"Other", nil];
        // 2.显示UIActionSheet
        [sheet showInView:self.view];
      
        // 只要UIActionSheet上的按钮被点击就会调用
        // actionSheet:谁触发事件就会把谁传递进来
        // clickedButtonAtIndex:当前被点击按钮的索引
        -(void)actionSheet:(nonnull UIActionSheet *)actionSheet      clickedButtonAtIndex:(NSInteger)buttonIndex
        {
          NSLog(@"%ld", buttonIndex);
        }
      
    • UIAlertView

            UIAlertView *alert = [[UIAlertView alloc]        initWithTitle:@"哥是标题" message:@"姐是正文..." delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
        alert.alertViewStyle =  UIAlertViewStyleLoginAndPasswordInput;
      
             [alert show];
      
      • 只要UIAlertView上的按钮被点击, 就会调用 alertView:谁触发事件就会把谁传递进来 ButtonAtIndex: 当前被点击按钮的索引
            -(void)alertView:(UIAlertView *)alertView    clickedButtonAtIndex:(NSInteger)buttonInde
           {
        // 取消 = 0, 确定 = 1 , 其他 = 2 , Other = 3 以此类推
        switch (buttonInde)
                {
            case 0:
                NSLog(@"点击了取消");
                break;
            case 1:
                NSLog(@"点击了确定");
                break;
            case 2:
                NSLog(@"点击了其他");
                break;
            case 3:
                NSLog(@"点击了Other");
                break;
            default:
                break;
               }
      
          }
      
    • 代理的应用场景

      • A对象向监听B对象的变化, A对象就可以成为B对象的代理 B对象发生一些变化想通知A对象, 那么A对象就可以成为B对象的代理

      • 监听

        • 规律:
          • 1.以后但凡看到iOS中需要传递对象成为某个对象的代理, 那么直接写上某个对象的类名 + Delegate即可
          • 2.一般情况下, 代理中的方法都是以控件的名称去掉前缀开头
    • 自定义HUD

      // 1.创建父控件
        UIView *cover = [[UIView alloc] init];
        cover.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
        cover.frame = CGRectMake(0, 0, 150, 150);
        cover.center = self.view.center;
      
        // 修改父控件为圆角
        cover.layer.cornerRadius = 10;
        [self.view addSubview:cover];
      
        // 2.创建菊花
        // 菊花有默认的尺寸
        // 注意: 虽然有默认的尺寸, 但是要想显示必须让菊花转起来
        UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        activity.center = CGPointMake(cover.frame.size.width * 0.5, 50);
        [activity startAnimating];
      
        [cover addSubview:activity];
        // 3.创建UILabel
        UILabel *label = [[UILabel alloc] init];
        //    label.backgroundColor = [UIColor purpleColor];
        label.textAlignment = NSTextAlignmentCenter;
        label.text = @"正在拼命加载中...";
        label.frame = CGRectMake(0, cover.frame.size.height - 80, cover.frame.size.width, 80);
        [cover addSubview:label];
      
    • 自定义按钮

      • 注意: 不能在外界直接修改UIButton内部的子控件的frame
        这是不可以的
        XMGButton *btn = [[XMGButton alloc] init];
        btn.imageView.frame = CGRectMake(0, 0, btn.frame.size.width, btn.frame.size.width);
        
      • 需要在自定义按钮类实现中重写如下方法才可以修改UIButton内部的子控件的frame

        • 该方法用于返回按钮内部标题的尺寸和位置
        • 该方法是由系统自动调用的
        • 系统每次调用该方法, 都会将父控件的frame传递进来
        • contentRect: 父控件的frame
        • 该方法用于返回按钮内部的图片的尺寸和位置

          -(CGRect)imageRectForContentRect:(CGRect)contentRect
          {
            // x = 0, y = 0, width = 父控件的宽度, height =                       父控件的宽度
           return CGRectMake(0, 0, contentRect.size.width,         contentRect.size.width);;
           }
          
          -(CGRect)titleRectForContentRect:(CGRect)contentRect
          {
          // x = 0, y = 父控件的宽度 width =  父控件的宽度, height = 父控件的高度 - 父控件的宽度
          return CGRectMake(0, contentRect.size.width, contentRect.size.width, contentRect.size.height - contentRect.size.width);
          }
          
          • UIButton内部的子控件的frame还可以用-(void)layoutSubviews方法实现
      • UIButton内边距

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [btn setImage:[UIImage imageNamed:@"024"] forState:UIControlStateNormal];
        [btn setTitle:@"贵宾" forState:UIControlStateNormal];
        btn.frame = CGRectMake(100, 100, 145, 60);
        // 上左下右
        // 如果是设置contentEdgeInsets, 会把UIImageView和UIlabel当做一个整体移动
        // 如果是设置titleEdgeInsets/imageEdgeInsets. 那么不会影响到另外一个, 也就是只会改变当前设置的这个控件
        btn.contentEdgeInsets = UIEdgeInsetsMake(20, 0, 0, 0);
        btn.titleEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0);
        btn.imageEdgeInsets = UIEdgeInsetsMake(50, 0, 0, 00);
        [self.view addSubview:btn];
        
    • 图片拉伸

         UIButton *btn = [[UIButton alloc] init];
        UIImage *image = [UIImage imageNamed:@""];
      
        // 1.iOS5以前
      /*
        // LeftCapWidth: 左边多少不能拉伸
        // 右边多少不能拉伸 = 控件的宽度 - 左边多少不能拉伸 - 1
        //  right  =  width - leftCapWidth - 1
        // 1 = width - leftCapWidth - right
      
        // topCapHeight: 顶部多少不能拉伸
        // 底部有多少不能拉伸 = 控件的高度 - 顶部多少不能拉伸 - 1
        //  bottom =  height - topCapWidth - 1
        // 1 = height - topCapWidth - bottom
        UIImage *newImage = [image stretchableImageWithLeftCapWidth:5 topCapHeight:5];
      */
      
        // 2.iOS5开始
        /*
        // UIEdgeInsets是告诉系统哪些地方需要受保护, 也就是不可以拉伸
        // resizableImageWithCapInsets默认拉伸方式是平铺
        UIEdgeInsets insets = UIEdgeInsetsMake(image.size.height * 0.5, image.size.width * 0.5, image.size.height * 0.5, image.size.width * 0.5);
        UIImage *newImage =  [image resizableImageWithCapInsets:insets];
         */
      
        // 3.iOS6开始
        /*
        // resizingMode指定拉伸模式
        // 平铺
        // 拉伸
        UIEdgeInsets insets = UIEdgeInsetsMake(5, 5, 5, 5);
        UIImage *newImage =  [image resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch];
        */
        [btn setBackgroundImage:newImage forState:UIControlStateNormal];
        btn.frame = CGRectMake(100, 100, 200, 80);
        [self.view addSubview:btn];
      
    • KVC
            Person *p = [Person new];
            p.name = @"lmj";
            p.money = 998;
    
      #pragma mark 获取单个值
        NSString *name =[p valueForKey:@"name"];
        NSLog(@"name = %@",name);
        double money =[[p valueForKey:@"money"] doubleValue];
        NSLog(@"money = %f", money);
    
    
       #pragma mark 获取多层值
       NSString *dogName = [p valueForKey:@"dog.name"];
       NSString *dogName = [p valueForKeyPath:@"dog.name"];
       NSLog(@"dogName = %@", dogName);
    
        #pragma mark 模型转字典
        NSDictionary *dict = [p dictionaryWithValuesForKeys:@[@"name",       @"money"]];
        NSLog(@"%@", dict);
    
    
       #pragma mark 获取数组中对象的值
    
        Person *p1 = [Person new];
        p1.name = @"zs";
        p1.money = 111;
    
        Person *p2 = [Person new];
        p2.name = @"ls";
        p2.money = 222;
    
        Person *p3 = [Person new];
        p3.name = @"ww";
        p3.money = 666;
    
        NSArray *arr = @[p1, p2, p3];
    
        // 如果数组中的元素都是同一种类型的数据,  可以使用KVC获取数组中所有对象的某个属性的值
        NSArray *res = [arr valueForKeyPath:@"name"];
        NSLog(@"res = %@", res);
    
    
      #pragma mark 运算符
        id res1 = [arr valueForKeyPath:@"@avg.money"];
        NSLog(@"res = %@", res1);
    
    }
    
    - (void)kvcSetter
    {
        Person *p = [[Person alloc] init];
        //    p.name = @"lnj"; // setter
        //    p.money = 998.0;
    #pragma mark 单个值
        /*
         //      KVC == KEY VALUE CODING
         // Value : 值, 只能传对象
         // forKey: 需要给谁(哪个属性)赋值
         // setValue:forKey:方法, 只能给对象的直接属性赋值
         [p setValue:@"lmj" forKey:@"name"];
         // @(998.0) == [NSNumber numberWithDouble:(double)]
         [p setValue:@(668.0) forKey:@"money"];
         */
    
    #pragma mark 多层赋值
        p.dog = [Dog new];
        /*
         //    p.dog.name == [[p dog] setName:]
         //    p.dog.name = @"wangwang";
         //    p.dog.price = 110.0;
         // setValue:forKeyPath: 可以给对象的间接属性赋值. 多层赋值
         // 建议: 以后在开发中都使用setValue:forKeyPath:
         //    [p setValue:@"xiaoqiang" forKeyPath:@"dog.name"];
         //    [p setValue:@(110) forKeyPath:@"dog.price"];
          */
    #pragma mark 给私有成员变量赋值
        /*
         //    [p setValue:@"lnj" forKey:@"_name"];
         //    [p setValue:@(30) forKey:@"_age"];
    
         //    SEL sel = @selector(say);
         //    [p performSelector:sel];
         //    [p say];
         */
    
    #pragma mark 字典转模型
    
        NSDictionary *dict = @{
                               @"name":@"xxx",
                               @"money": @(998.1),
                               //                           @"score":@(100)
                               @"dog":@{
                                       @"name":@"wangcai",
                                       @"price":@(110)
                                       }
                               };
    
        //    p.name = dict[@"name"];
        //    p.money =[dict[@"money"] doubleValue];
    
    
        // 注意点:
        // 1.如果想使用KVC进行字典转模型, 那么字典中的key必须和模型中的属性一模一样(个数 + 名称)
        //  this class is not key value coding-compliant for the key score.'
        // 2.如果使用KVC进行字典转模型, 只能对当前调用KVC方法的对象进行转换, 不能对它的属性的对象进行转换
    
        // setValuesForKeysWithDictionary:方法内部的实现原理
        // 1.会拿到字典中的key, 然后根据这个key取出字典中的值, 然后再根据这个key赋值给对象
        //   [p setValue:@"xxx" forKey:@"name"];
        [p setValuesForKeysWithDictionary:dict];
    
        NSLog(@"p.dog = %@", p.dog);
    
        NSLog(@"name = %@, money = %f", p.name, p.money
    
    • KVO
         //    KVO == Key Value Observing
    //    作用: 可以监听某个对象属性的改变
    
        Person *p = [Person new];
        p.name = @"lnj";
        p.age = 30;
    
        /*
         第一个参数: 告诉系统哪个对象监听
         第二个参数: 监听当前对象的哪个属性
         第三个参数: 监听到属性改变之后, 传递什么值
         第四个参数: 需要传递的参数 (这个参数不是传递给属性的)
         */
        // 给p这个对象添加一个监听 , 监听p对象的age属性的改变, 只要age属性改变就通知self
        [p addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
    
        p.age = 50;
    
        NSLog(@"-------------------");
    
    //    p.age = 100;
    
        // 注意: 如果使用KVO监听某个对象的属性, 当对象释放之前一定要移除监听
        //  reason: 'An instance 0x7f9483516610 of class Person was deallocated while key value observers were still registered with it.
        // 注意: KVO只能监听通过set方法修改的值
        /*
         KVO的原理:
         只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象,
         并且重写自动生成的子类对象的被监听属性的set方法, 然后在set方法中通知监听者
         NSKVONotifying_Person
         */
        p->_age = 998;
    
        // 从p对象上移除self对它的age属性的监听
        [p removeObserver:self forKeyPath:@"age"];
    
     // 只要监听到属性的改变就会调用
    // keyPath: 被监听的属性名称
    // object : 被监听的对象
    // context: 注册监听的时候传入的值
    - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
    {
        NSLog(@"keyPath = %@, object = %@ , change = %@, context = %@", keyPath, object, change, context);
    }
  • 相关阅读:
    GoF23种设计模式之己见
    全面阐述某系统设计所实现的质量属性战术
    对XX系统的可用性和易用性改良
    《淘宝网》的质量属性描述
    读《架构漫谈》之后
    软件架构之再理解
    《架构之美》阅读笔记06
    《架构之美》阅读笔记05
    《架构之美》阅读笔记04
    《架构之美》阅读笔记03
  • 原文地址:https://www.cnblogs.com/liujiaoxian/p/4697057.html
Copyright © 2011-2022 走看看