iOS 开发实训第七周周报

一、学习笔记

  • 根据十六进制的色号来设置颜色:

    • 使用Category,为UIColor类添加将解析十六进制色号为RGB值的方法

    • UIColor+Hex.h

      #import <UIKit/UIKit.h>
      
      NS_ASSUME_NONNULL_BEGIN
      
      @interface UIColor (Hex)
      
      // 默认alpha为1
      + (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue;
      
      // 从十六进制字符串获取颜色,默认alpha为1 color支持@“#123456”, @“0X123456”, @“123456”三种格式
      + (UIColor *)colorWithHexString:(NSString *)color;
      
      // 从十六进制字符串获取颜色,alpha需要自己传递 color支持@“#123456”, @“0X123456”, @“123456”三种格式
      + (UIColor *)colorWithHexString:(NSString *)color alpha:(CGFloat)alpha;
      
      @end
      
      NS_ASSUME_NONNULL_END
      
    • UIColor+Hex.m

      #import "UIColor+Hex.h"
      
      @implementation UIColor (Hex)
      
      + (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue {
          return [UIColor colorWithRed:red green:green blue:blue alpha:1];
      }
      
      + (UIColor *)colorWithHexString:(NSString *)color alpha:(CGFloat)alpha {
          // 删除字符串中的空格
          NSString *cString = [[color stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
          // 得到的字符串的长度应该是6或者8
          if ([cString length] < 6) {
              return [UIColor clearColor];
          }
      
          // 如果是0x开头的,那么截取字符串,字符串从索引为2的位置开始,一直到末尾
          if ([cString hasPrefix:@"0X"]) {
              cString = [cString substringFromIndex:2];
          }
          // 如果是#开头的,那么截取字符串,字符串从索引为1的位置开始,一直到末尾
          if ([cString hasPrefix:@"#"]) {
              cString = [cString substringFromIndex:1];
          }
          if ([cString length] != 6) {
              return [UIColor clearColor];
          }
          
          // 将字符串分为r,g,b三个分量
          NSRange range;
          range.location = 0;
          range.length = 2;
          NSString *rString = [cString substringWithRange:range];
          range.location = 2;
          NSString *gString = [cString substringWithRange:range];
          range.location = 4;
          NSString *bString = [cString substringWithRange:range];
          
          // 将字符串十六进制两位数字转为十进制整数
          unsigned int r, g, b;
          [[NSScanner scannerWithString:rString] scanHexInt:&r];
          [[NSScanner scannerWithString:gString] scanHexInt:&g];
          [[NSScanner scannerWithString:bString] scanHexInt:&b];
          
          // 返回对应的颜色对象
          return [UIColor colorWithRed:((float)r / 255.0f) green:((float)g / 255.0f) blue:((float)b / 255.0f) alpha:alpha];
      }
      
      // 默认alpha值为1
      + (UIColor *)colorWithHexString:(NSString *)color {
          return [self colorWithHexString:color alpha:1.0f];
      }
      
      @end
      
  • OC中继承、分类、扩展的对比:

    • 继承:
      • OC中的继承与C++中的一样,实现继承的子类将拥有父类所有的属性和方法,子类可以重写父类的方法,可以通过super调用父类的方法;但是与C++不同的是,OC中只能单继承
    • 分类 Category:
      • 分类是OC特有的属性,利用OC的动态运行时分配机制,在现有类的基础上添加新的方法,也可以添加成员变量(不能是原有类的成员变量),但是添加的成员变量不会自动生成settergetter方法,需要在@implement中自己实现
      • 不能在分类中定义与原有类同名方法,不同的分类之间也不可以有同名的方法,如果在分类中增加了一个与原有类同名的方法,那么分类中的方法会覆盖原有类的方法,如果多个分类中有相同的方法,执行最后编译的方法
    • 拓展 Extension:
      • 拓展就是匿名的分类,只有.h文件没有.m文件,原类名称后面的括号中没有东西,只能扩展方法,不能添加成员变量,类扩展得到的属性和方法都是私有的,扩展的方法只能在原类中实现,外部无法调用
  • 成员变量和属性的区别:

    @interface Person : NSObject {
        NSString *sex; // 成员变量
    }
    @property (nonatomic, copy) NSString *name; // 属性
    
    @end
      
    @implementation Person {
      @public NSInteger *age; // 成员变量
    }
    
    • 成员变量:(实际开发中很少使用)
      • 成员变量能声明作用范围,各修饰符的作用范围如下:
        • @public:在任何地方都能直接访问对象的成员变量
        • @private:只能在当前类的对象方法中直接访问,如果子类要访问需要调用父类的getter/setter方法
        • @protected:可以在当前类及其子类对象方法中直接访问(系统默认下是用它来修饰的)
        • @package:在同一个包下就可以直接访问,比如说在同一个框架
      • 如果没有显式声明,则在.m中的成员变量默认为private,在.h中的成员变量默认为protected
      • 无论父类是在@interface还是@implementation声明的成员变量子类都能拥有,但是子类能不能直接通过变量名来访问父类中定义的成员变量是需要看父类中定义的成员变量是由什么修饰符来修饰的
      • 成员变量不会自动生成getter/setter方法,需要自己手动实现
      • 成员变量不能用点语法调用,因为没有getter/setter方法,只能使用self->调用
    • 属性:
      • 属性的默认修饰是@protected
      • 属性会自动生成getter/setter方法
      • 属性用点语法调用,点语法实际上调用的是getter/setter方法
  • 将视图移到界面最前方:

    • 调用父视图的bringSubviewToFont方法(将视图移到最后面则调用父视图的sendSubviewToBack方法)
    • [[[UIApplication sharedApplication] keyWindow] addSubview:view];
  • OC函数前面加-+的区别:

    • +修饰的方法称为类方法,可以通过类名直接调用(类似于JAVA中的static方法)
    • -修饰的方法称为对象方法,只能实例化一个对象然后通过该对象来调用
  • iOS中触摸事件传递机制:

    • 只有继承自UIResponder的类才能接收并处理触摸事件,包括UIApplicationUIViewControllerUIViewUIResponder中提供了以下四个对象方法来处理触摸事件

      - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
      - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
      - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
      - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
      
    • 事件处理的整个流程总结:

      • 触摸屏幕产生触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中(即首先接收到事件的是UIApplication
      • UIApplication会从事件队列中取出最前面的事件,把事件传递给应用程序的主窗口keyWindow
      • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件
      • 最合适的view会调用自己的touches方法处理事件
      • touches默认做法是把事件顺着响应者链条向上抛

二、遇到的问题及解决方法

  • 实现了点击某个按钮显示下拉菜单之后,如何实现点击其他位置关闭该下拉菜单:

    • 核心思路是在touchesBegan中判断触摸点是否属于下拉菜单,如果不属于就隐藏下拉菜单

      - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
          CGPoint point = [[touches anyObject] locationInView:self];
          point = [self.alertView.layer convertPoint:point fromLayer:self.layer];
          if (![self.alertView.layer containsPoint:point]) {
              self.hidden = YES;
          }
      }
      

      但是这个方法存在一个问题,因为页面中有UISearchBarControllerUIScrollViewControllerUITableViewController,这些ViewController不会把触摸事件传递给父控件,有两种解决方法:

      • 方法一:重写UISearchBarControllerUIScrollViewControllerUITableViewControllertouchesBegan方法,将触摸事件传递到最底层的UIView
      • 方法二:(这种方法是我自己想到的,不知道会不会有什么问题)因为显示下拉菜单后,点击其他位置的效果都应该只能起隐藏下拉菜单的效果,而UISearchBarControllerUIScrollViewControllerUITableViewController不应该响应,所以可以在下拉菜单下面加一层透明的UIView,这样下拉菜单显示时点击其他位置都会触发该ViewtouchesBegan方法,隐藏下拉菜单后再将这层UIView也隐藏即可

三、参考链接


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值