• 百思不得姐第4天:文本框占位文字颜色


    一:设置登录界面和注册界面的切换

    #import "CQLoginViewController.h"
    #import "CQCustomTextField.h"
    @interface CQLoginViewController ()
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *centerTopConstraints;
    @property (weak, nonatomic) IBOutlet UIButton *loginbtn;
    @property (weak, nonatomic) IBOutlet CQCustomTextField *loginScreenField;
    @property (weak, nonatomic) IBOutlet CQCustomTextField *loginPhoneField;
    @property (weak, nonatomic) IBOutlet CQCustomTextField *registScreenField;
    @property (weak, nonatomic) IBOutlet CQCustomTextField *registPhoneField;
    
    @end
    
    @implementation CQLoginViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //1:设置登陆注册按钮的圆角效果
        
        /**
         1:
          [self.loginbtn setValue:@YES forKeyPath:@"layer.masksToBounds"];
          [self.loginbtn setValue:@6 forKeyPath:@"layer.cornerRadius"];
         
         2:  self.loginbtn.layer.masksToBounds = YES;
             self.loginbtn.layer.cornerRadius = 6;
         
         3:可以在xib中设置其圆角效果:设置keypath路径即可
         */
        
    }
    
    #pragma mark -- 注册按钮的点击事件
    - (IBAction)registBtn:(UIButton *)sender {
        
        //根据点击的不同的按钮来显示登陆或是注册的文本框
        /**
         * 1:可以根据btn.currentTile来判断 2:根据按钮的选中状态来判断 3:根据约束值来判断
         */
        
        
        //1:先退去键盘
        [self.view endEditing:YES];
        
        
        //2:偏移view
        sender.selected = !sender.isSelected;
        
        self.centerTopConstraints.constant = sender.isSelected ? (- self.view.CQ_Width) : 0;
        
        [UIView animateWithDuration:0.5 animations:^{
            // 强制刷新 : 让最新设置的约束值马上应用到UI控件上
            // 会刷新到self.view内部的所有子控件
            [self.view layoutIfNeeded];
        }];
        
    }
    
    #pragma mark -- 取消按钮点击事件
    - (IBAction)cancleBtn:(UIButton *)sender {
        
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    #pragma mark -- 修改状态栏的样式
    
    - (UIStatusBarStyle)preferredStatusBarStyle {
        
        return UIStatusBarStyleLightContent;
    }
    
    #pragma mark -- 点击空白处退去键盘
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        [self.view endEditing:YES];
    }
    @end

    总结:1:设置登陆按钮的圆角效果:1:直接设置按钮的layer,若是表格视图,不建议通过layer设置圆角效果,会很耗性能,最好是通过绘图的方式设置圆角效果  2:利用kvc也可以设置圆角效果,kvc一般都是为属性赋值,setValue forKey直接为属性赋值,setValue forKeyPath为属性的路径赋值,属性的属性:

     [self.loginbtn setValue:@YES forKeyPath:@"layer.masksToBounds"];
     [self.loginbtn setValue:@6 forKeyPath:@"layer.cornerRadius"];
    3:可以在xib中设置其圆角效果:设置keypath路径即可

    2:一个按钮的切换:1:sender.selected = !sender.isSelected; 2:三个按钮的切换:设置currentBtn,按钮的三部曲

    3:在xib中登陆界面,删除左侧的间距约束,拖线左侧约束到控制器,根据按钮的状态设置左侧的约束值。再在UIView的动画里强制刷新UI:
      [UIView animateWithDuration:0.5 animations:^{
            // 强制刷新 : 让最新设置的约束值马上应用到UI控件上
            // 会刷新到self.view内部的所有子控件,立即调用layoutsubview,刷新UI视图
            [self.view layoutIfNeeded];
        }];
    4:设置状态栏的样式或是显示隐藏:就在控制器内设置:
    - (UIStatusBarStyle)preferredStatusBarStyle {
        
        return UIStatusBarStyleLightContent;
    }


    二:封装占位文字
    #import <UIKit/UIKit.h>
    
    @interface UITextField (XMGExtension)
    /** 占位文字颜色 */
    @property (nonatomic, strong) UIColor *placeholderColor;
    @end
    #import "UITextField+XMGExtension.h"
    
    static NSString * const XMGPlaceholderColorKey = @"placeholderLabel.textColor";
    
    @implementation UITextField (XMGExtension)
    
    - (void)setPlaceholderColor:(UIColor *)placeholderColor
    {
        // 提前设置占位文字, 目的 : 让它提前创建placeholderLabel
        NSString *oldPlaceholder = self.placeholder;
        self.placeholder = @" ";
        self.placeholder = oldPlaceholder;
        
        // 恢复到默认的占位文字颜色
        if (placeholderColor == nil) {
            placeholderColor = [UIColor colorWithRed:0 green:0 blue:0.0980392 alpha:0.22];
        }
        
        // 设置占位文字颜色
        [self setValue:placeholderColor forKeyPath:XMGPlaceholderColorKey];
    }
    
    //- (void)setPlaceholderColor:(UIColor *)placeholderColor
    //{
    //    // 提前设置占位文字, 目的 : 让它提前创建placeholderLabel
    //    if (self.placeholder.length == 0) {
    //        self.placeholder = @" ";
    //    }
    //    
    //    [self setValue:placeholderColor forKeyPath:XMGPlaceholderColorKey];
    //}
    
    - (UIColor *)placeholderColor
    {
        return [self valueForKeyPath:XMGPlaceholderColorKey];
    }
    
    @end

    总结:1:在分类中不能为类扩充属性,在分类中以属性定义变量,此时不会自动生成带下划线的成员变量,需要自己手动去实现set和get方法,若想拥有带下划线的成员变量,则可以static定义全局变量,在get方法中可以返回。

            2:当外界传进来参数的时候,严谨一些最好要先判断外界传进来的值是否为空,为空return返回或是设置默认值,不为空可以利用kvc为属性赋值,在get方法中,再利用kvc valueForKeyPath 取出值并返回

    
    
    #import "CQCustomTextField.h"
    #import <objc/runtime.h>
    @implementation CQCustomTextField
    
    /**
     *    1:从xib中加载完成后会调用,可以在此方法中设置一些一次性代码,类似于init方法来设置一次性代码 2:注意的是当执行完此方法后,子控件的数组个数为0
     */
    - (void)awakeFromNib {
        
        //1:改变光标的颜色
        self.tintColor = [UIColor whiteColor];
        self.textColor = [UIColor whiteColor];
        
        //2:改变占位文字的默认颜色
        self.CQ_placeHolderColor = [UIColor lightGrayColor];
    
    }
    
    /**
     *
     *
     *    @return <#return value description#>
     */
    - (BOOL)becomeFirstResponder {
        
       self.CQ_placeHolderColor = [UIColor whiteColor];
       return [super becomeFirstResponder];
    }
    
    - (BOOL)resignFirstResponder {
        
        self.CQ_placeHolderColor = [UIColor lightGrayColor];
        return [super resignFirstResponder];
    }
    
    
    
    /**
     *    1:可以改变Placeholder的颜色和字体大小,和内容
        2:在textField要显示的时候调用
    - (void)drawPlaceholderInRect:(CGRect)rect {
     
     [@"123" drawInRect:CGRectMake(5, 10, 40, self.CQ_Height - 20) withAttributes:@{NSFontAttributeName : Font(13),NSForegroundColorAttributeName : [UIColor whiteColor]}];
     }
    
     */
    
    /**
     *    
     1:此方法是改变占位文字的颜色:遍历子控件,父类的指针指向子类,找到关联的对象设置属性 2:但是在xib中的awakeFromeNib中子控件数组为0,所以无法设置默认的placeholder的颜色
     
     - (void)layoutSubviews {
     
     [super layoutSubviews];
     
     for (UIView *view in self.subviews) {
     
     if (![view isKindOfClass:NSClassFromString(@"UITextFieldLabel")]) continue;
     
     UILabel *lable = (UILabel*)view;
     lable.textColor = [UIColor redColor];
     }
     
     }
     */
    
    /**
     *    runtime:找到某个类的所有下划线的成员变量,包括类私有的不公开的,利用kvc,valueforkeypath,将其定义的私有属性取出,并修改其行为
     unsigned int count;//<#unsigned int *outCount#>:参数需要传入一个指针
     Ivar *ivarList = class_copyIvarList([UITextField class], &count);
     
     for (int  i = 0; i < count ; i++) {
     
     Ivar var = ivarList [i];
     CQLog(@"----------------------------%s", ivar_getName(var));
     }
     
     free(ivarList);
    
     */
    
    
    
    @end

    总结:1:自定义UITextField类与xib中的文本框相关联,在xib中,关联自定义的类UITextField,在自定义类UITextField实现awakfromNib: 1:awakfromNib:从xib中加载完成后会调用,可以在此方法中设置一些一次性代码,类似于init方法来设置一次性代码 2:注意的是当执行完此方法后,子控件的数组个数为0。在此方法内设置光标的颜色和文字颜色占位文字默认颜色:  self.tintColor = [UIColor whiteColor];  self.textColor = [UIColor whiteColor];self.CQ_placeHolderColor = [UIColor lightGrayColor];

            2:监听文本框的第一响应:就重写系统的- (BOOL)becomeFirstResponder,调用时刻 : 成为第一响应者(开始编辑弹出键盘获得焦点),重写此方法不要忘记调用super,否则就不能响应父类的方法,不能响应键盘事件弹出键盘。先设置占位文字颜色

    - (BOOL)becomeFirstResponder

    {

        self.placeholderColor = [UIColor whiteColor];

        return [super becomeFirstResponder];

    }

    /**

     *  调用时刻 : 不做第一响应者(结束编辑退出键盘失去焦点)

     */

    - (BOOL)resignFirstResponder

    {

        self.placeholderColor = [UIColor grayColor];

        return [super resignFirstResponder];

    }

    3:找到设置textField占位文字颜色的属性:1:自定义类继承系统的UITextField,在layoutsubView方法里看看是否能直接拿到该属性设置 (当在方法layoutsubView设置约束的时候,配合setNeedslayout,或是layoutifNeed来更新约束)2:若不能直接拿到该属性,则可以遍历子控件数组并打印,拿到所有的子控件,在遍历方法中(for in index++,for int i,enum,先做条件过滤,return,continue,或是break,拿到属性之后(父类的指针可以指向子类),去设置属性,找到以后并停止遍历。)找到对应的属性后,设置属性值。

    - (void)layoutSubviews {

      [super layoutSubviews];

     for (UIView *view in self.subviews) {

      if (![view isKindOfClass:NSClassFromString(@"UITextFieldLabel")]) continue;

      UILabel *lable = (UILabel*)view;

     lable.textColor = [UIColor redColor];

     }

     }

     4:查找系统的API,子类或是父类中有没有方法设置占位文字的颜色,可以搜索placeHolder,或是搜索placeHolderColor,来查看。在系统的方法中可以找到drawRect方法:

     1:可以改变Placeholder的颜色和字体大小,和内容

     2:在textField要显示的时候调用:drawRect方法都是在控件即将显示的时候被调用

    - (void)drawPlacedholderInRect:(CGRect)rect {

      [@"123" drawInRect:CGRectMake(5, 10, 40, self.CQ_Height - 20) withAttributes:@{NSFontAttributeName : Font(13),NSForegroundColorAttributeName : [UIColor whiteColor]}];

     }

    5:利用runtime挖掘系统的私有属性:

    runtime: class_copyIvarList方法找到某个类的所有下划线的成员变量,包括类私有的不公开的,利用kvc,valueforkeypath,将其定义的私有属性取出,并修改其行为

     unsigned int count;

    //unsigned int *outCount:unsigned为无符号整型,也就是都为正数,不为负数, int *outCount参数:outCount是一个指针,也就是需要传入一个内存地址,也就是&count。当该方法执行完毕后,系统会根据内存地址,找到该变量,为该变量赋值

    //此时的ivarList相当于一个数组,遍历ivarList,取出的元素是Ivar类型的元素,ivar_getName(var)获取ivar元素的属性名字

     Ivar *ivarList = class_copyIvarList([UITextField class], &count);

      for (int  i = 0; i < count ; i++) {

     Ivar var = ivarList [i];

     CQLog(@"----------------------------%s", ivar_getName(var));

     }

     free(ivarList);//释放ivarList

    6:自定义控件继承系统控件:利用kvc替换掉系统控件:还可以用封装继承,新建类继承系统的控件,layoutSubView中可以重新布局子控件,遍历子控件数组,找到去设置再利用kvc替换掉系统的控件

     6:补充:

    1:

    如图所示,当如图所示的按钮时,可以让按钮平分整个间距。类似于底部tabBar按钮的结构,平分整个tabBar的宽度

    当设置约束的时候,1:三个等宽登高,可以同时选中设置,equalWidth,和equalHeight  2:当去清除约束的时候,注意需要清除的是当前的约束还是全部约束。1;在xib中如何设置三个等宽登高且平分屏幕宽度。1;先设置中间按钮的顶部间距,和高度约束,2:后两个按钮通过拉线设置顶部对其,确定顶部约束,再同时选中三个,右下角同时设置三个按钮登高,等宽,在设置第一个按钮的最左边按钮左间距为0,最后一个按钮的右间距为0,同时在设置两两间距为0,3:如图:当是上下左右的时候点击小箭头,会有和子控件的约束。(此处可以设置子控件与父控件的间距约束,如图所示,它所设置的约束,是距离该控件最近的控件)

     

    2:又有图片又有文字的,就用button,如网易新闻导航标题。上部为图片下部为文字的,1:就自定义button,继承UIButton,实现button的设置title,Image的改变frame的方法。2:就自定义button,继承UIButton:在layoutsubView里可以直接拿到btn的iamge和lable去设置frame,若是不能直接拿到,则遍历子控件数组(遍历条件),打印,NSClassFromstring,取出 ,停止遍历,若是遍历找不到,runtime,class_copyIvarlist查找其所有属性变量,利用kvc取出或是进行赋值  3:利用btn的内边距,先整体内容左对齐(继承UIControl的方法),在调节contentEdge,titleEdge,imageEdge  2:当控件从xib中加载完成后,就会调用awakefromNib,可以在此方法中进行一些控件的固定内容或是设置属性等工作,此方法调用完毕后子控件数组个数依然为0。3:若想自定义xib中的按钮,则新建类继承UIButton,先在xib中关联类,如图:关联类后可以在该类中实现awakefromNib就可以直接在该类中去设置xib中的button

    3:1:设置控件的frame在layoutSubView里最为严禁,super 调用了layoutSubView,则父类已将子控件的的frame设置好,在设置frame写在下面是覆盖掉super的行为,重新定义frame。2:当每次要重新布局子控件时,就要想到用到layoutsubView,配合layoutifNeeded(立即调用layoutsubView刷新frame),setNeedslayout(异步调用layoutsubView)一起使用。3:如果是更改系统控件的frame,可以通过继承,先继承系统的控件,重写layoutsubView,1:直接拿到系统控件公开的属性去设置frame  2:若是没有公开的属性去设置,要拿到想要更改的子控件,可以遍历子控件的数组,条件过滤continue,找到,重新设置frame,并停止遍历。3:若还是找不到可以在系统API中子类或是父类中搜索相关属性去设置 4:利用runtime的方法class_copyIvarList去拿到系统类所有带下划线的成员变量,利用kvc可以为属性或是带下划线的成员变量赋值,还可以valurForkey或是keyPath将值取出来。

    4:事件传递响应简单概述:

    点击view的空白处dissMiss掉之前的控制器,实现touchBegan方法,必须该控件要开启用户的交互权限,且只有点击空白处才会消失,若是点击的是其他的按钮,则被点击的按钮会响应该事件,不会实现touchbegan方法。因为的传递:事件的传递是由父控件传递到子控件,在传递过程中先看该控件能否与用户进行交互,不能则事件传递直接终止,若能则会看触摸点是不是在该ew上,两个底层方法:pointInside,hitTest(在父类中实现这两个方法可以返回处理该事件的view和返回触摸点是否在自身),就这样一级一级传递直到找到最合适的view来响应事件。找到最合适的view后,再看看该view能否否处理响应事件,若不能处理则交会沿着响应者链向上传递给父控件去处理。

    5:设置xib的约束:

    xib设置约束的时候:1:拉线和右下角配合使用,右下角倒数第一个有清除所有约束,清除部分约束,更新frame(改变的时候就需要更新)倒数第二个,可设置上下左右间距,宽高,等宽登高,选择第二个,再添加约束,小箭头也可以点击,表示距那个控件的上下左右。倒数第三个可设置距离父控件的中心点 2:一般封装时,会有父控件view,先固定父控件view,再往里面添加子控件,当子控件约束确定后,再去除父控件的高度,也就是让父控件的高度等于子控件的高度,前提是设置父控件中最后一个子控件底部bottom与父控件的底部bottom的约束必须设置,这样就可以让父控件的高度等于子控件的高度。最好可以给xib控件写注释 2:背景图片的UIImageView到底设多大??就查看背景图片为多少像素,UIIMgaeView就设置为多大,若背景图片很小时,则可以给UIimage写一个分类,来拉伸图片的宽高中心点。3:当xib设置约束的时候,也可以来到最左边,通过写注释的那个,选中A将A拖向B,弹出菜单,在设置约束,设置约束的时候还可以设置对其方式,左对齐,上不对齐,右部对齐。高度为父控件的一半,先设为与父控件登高,再来到右侧的约束界面,双击登高约束,:A等于B乘以1+0,可以改变乘以的数为0.5,则设置好了约束。如图:底部的textField直接拷贝控件,拷贝控件的时候,只拷贝了宽高,其他约束都没有去设置 4:

    在设置textField的时候:1:可以选择textField的style样式,clearBtn的样式,键盘的样式,keyBoard样式。2:xib若想完整的显示高亮状态下button的图片:按钮样式必须为设为custom .3:给button设置圆角效果需要拿到图层:self.loginButton.layer.cornerRadius = 5;self.loginButton.layer.masksToBounds = YES; 或是代码利用kvc实现:setValue forKeyPath :[self.loginButton setValue:@5 forKeyPath:@"layer.cor

    erRadius"];[self.loginButton setValue:@YES forKeyPath:@"layer.masksToBounds”];第二个参数为[self.loginButton的属性。还可以在xib中设置button的圆角效果:xib中也可以实现kvc,其中在xib中控制器view的xib也可以实现lvc赋值(kvc,setValue forKeyPath,就是赋值)

    4:

    当用xib设置frame约束的时候:左边:1:可以更改各个控件的层级关系 ,拖动 2:可以设置注释标题,方便以后查看 3:还以按住control选中一个控件实现拉线:可以设置其左对齐,右对齐,上对齐,下对齐和其他的约束 4:在中间就设置其center属性

    水平居中或是竖直居中。

    6:点击已有账号,注册和登陆界面的左右切换:

    设置的点击注册按钮,左右滑动。原以为是ScrollView,其实不是,是将另一个中间的view,copy了一份,更改了约束,设置在了屏幕的右端,对于左边的constrant约束,也可以拖线到控制器,通过更改其constranit,再在UIView的动画里强制立即刷新,来动画改变其左右滑动。但是左边约束删除,右边的与屏幕的约束删除约束,得删除,要不设置了右边的约束,当滑动的时候,view的最右边就会永远粘着右边。控制器代码:1:退出键盘的方式,self.view endEditing 2:取消键盘的第一响应者。2:按钮在不同的状态下显示不同的内容,那么久去设置按钮的不同状态下的属性,直接改变按钮的状态就可以了。3:重复点击按钮有不同的反应,1:可以根据按钮的状态去区分不同的行为,btn.selected = !btn.isselected; 2:还可以根据不同状态下的改变值,如获取btn不同状态下的标题,图片,背景图片,或是其他的变量,来区分按钮的不同的状态。3:self.leftMargin为一个模型,所以不能直接放在UIView的动画里,(UIView动画里设置frame,前提是得是frame具体值的改变,)可以在UIView动画外面设置模型或是frame的改变,在UIVIEW动画的内部,调用强制刷新的方法,用self.view去调用,则会刷新整个self.view的界面  [self.view layoutIfNeeded];调用此方法会立即执行刷新操作。刷新self.view里的所有子控件。

     7:富文本的简单使用:

    一:文字的富文本属性:

     设置textField的占位文字的颜色:

    // 设置占位文字内容

    @property(nullable, nonatomic,copy)   NSString               *placeholder;

    // 设置带有属性的占位文字, 优先级 > placeholder

    @property(nullable, nonatomic,copy)   NSAttributedString     *attributedPlaceholder;

    通过富文本属性来设置textField占位文字的颜色:

    1:## NSAttributedString

    - 带有属性的字符串, 富文本

    - 由2部分组成

        - 文字内容 : NSString *

        - 文字属性 : NSDictionary *

            - 文字颜色 - NSForegroundColorAttributeName

            - 字体大小 - NSFontAttributeName

            - 下划线 - NSUnderlineStyleAttributeName

            - 背景色 - NSBackgroundColorAttributeName

    - 初始化

    ```objc

    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];

    attributes[NSForegroundColorAttributeName] = [UIColor yellowColor];

    attributes[NSBackgroundColorAttributeName] = [UIColor redColor];

    attributes[NSUnderlineStyleAttributeName] = @YES;

    NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"123" attributes:attributes];

    ```

    - 使用场合

        - UILabel - attributedText

        - UITextField - attributedPlaceholder

        - textView-attributedText

    2:## NSMutableAttributedString

    - 继承自NSAttributedString

    - 常见方法

    ```objc

    // 用set设置range范围的属性, 重复设置同一个范围的属性, 最后一次设置才是有效的(之前的设置会被覆盖掉),而add是添加不覆盖,set是设置会覆盖

    - (void)setAttributes:(nullable NSDictionary<NSString *, id> *)attrs range:(NSRange)range;

    // 添加range范围的属性, 同一个范围, 可以不断累加属性

    - (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;

    - (void)addAttributes:(NSDictionary<NSString *, id> *)attrs range:(NSRange)range;

    ```

    6:一般涉及到显示文字的地方都可以使用富文本:例如新浪的发微博界面,titleView上下都有文字显示,1:可以封装一个大view,里面放两个lable,2:也可以使用富文本,其中设置lable的换行可用 ( 也算lable的字符串的一个字符),而且lable要是显示多行必须设置numberoflines = 0,设置的titleView:

      UILabel *label = [[UILabel alloc] init];

      // 设置属性文字

      NSString *text = @"你好 哈哈哈";

      NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];

      [attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:10] range:NSMakeRange(0, text.length)];

      [attributedText addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:13] range:NSMakeRange(3, 3)];// 也算是一个字符,所以从第三个字符开始

      label.attributedText = attributedText;

      // 其他设置

      label.numberOfLines = 0;

      label.textAlignment = NSTextAlignmentCenter;

      label.frame = CGRectMake(0, 0, 100, 40);

      [self.view addSubview:label];

      self.navigationItem.titleView = label;

    二:图文混排

    图文混排:图片和文字混排:先定义一个大的可变的富文本对象,把整体内容切分成若干个小的富文本,分别设置好小富文本属性后,拼接到大富文本的后面

       UILabel *label = [[UILabel alloc] init];

       label.frame = CGRectMake(100, 100, 200, 25);

       label.backgroundColor = [UIColor redColor];

       label.font = [UIFont systemFontOfSize:14];

       [self.view addSubview:label];

       // 图文混排:大富文本对象

       NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];

       // 1 - 你好:设置小富文本对象并拼接到大富文本对象后面

       NSAttributedString *first = [[NSAttributedString alloc] initWithString:@"你好"];

       [attributedText appendAttributedString:first];

       // 2 - 图片

       // 带有图片的附件对象

       NSTextAttachment *attachment = [[NSTextAttachment alloc] init];

       attachment.image = [UIImage imageNamed:@"header_cry_icon"];

       CGFloat lineH = label.font.lineHeight;//取出富文本中的字体高度

       attachment.bounds = CGRectMake(0, - ((label.xmg_height - lineH) * 0.5 ), lineH, lineH);

       // 将附件对象包装成一个属性文字

       NSAttributedString *second = [NSAttributedString attributedStringWithAttachment:attachment];

       [attributedText appendAttributedString:second];

       // 3 - 哈哈哈

       NSAttributedString *third = [[NSAttributedString alloc] initWithString:@"哈哈哈"];

       [attributedText appendAttributedString:third];

       label.attributedText = attributedText;

    其中:1:求label的字体高度: CGFloat lineH = label.font.lineHeight; 是为了让label的字体高度等于图片的高度。bonds可调整富文本中图片的frame,宽高为字体的宽高 2:调用系统的方法赋值,若是想在别处获得该值,则可调用系统的get方法获得所赋的值。3:富文本:有两部分组成:text和属性字典dic,分为可变和不可变,可变,则可以拼接其他富文本appendAtrtibuteString,设置富文本的内容,addAtrtibute,setAtribute,还可以根据范围去做设置

     8:画图修改textfield的占位文字颜色:可以重写drawRect 或是drawPoint 两个方法:1:返回的rect值为textField的矩形框 2:self.font 调用的就是textField中设置font的get方法 3:self.font.lineHeight 字体高度 3:range ,rect的结构体的写法,先定义一个rect,再赋值属性

    - (void)drawPlaceholderInRect:(CGRect)rect {

      // 文字属性

        NSMutableDictionary *attrs = [NSMutableDictionary dictionary];

        attrs[NSForegroundColorAttributeName] = [UIColor whiteColor];

        attrs[NSFontAttributeName] = self.font;

     // drawInRect画出占位文字

    //    CGRect placeholderRect;

    //    placeholderRect.size.width = rect.size.width;

    //    placeholderRect.size.height = self.font.lineHeight;

    //    placeholderRect.origin.x = 0;

    //    placeholderRect.origin.y = (rect.size.height - self.font.lineHeight) * 0.5;

    //    [self.placeholder drawInRect:placeholderRect withAttributes:attrs];

        

      // drawAtPoint画出占位文字 

        CGPoint placeholderPoint = CGPointMake(0, (rect.size.height - self.font.lineHeight) * 0.5);

        [self.placeholder drawAtPoint:placeholderPoint withAttributes:attrs];

    }

    修改textField的占位文字颜色:

    1:使用attributedPlaceholder  2:- (void)drawPlaceholderInRect:(CGRect)rect;,- (void)drawPlaceholderInRect:(CGRect)rect;  3:运行时查找系统类的私有变量:[textField setValue:[UIColor grayColor] forKeyPath:@"placeholderLabel.textColor"];

     9:scrollView的xib或是storyboard自动布局:

    scrollView的自动布局(xib或是storyBoard,纯xib):1:先增加一个子控件view到xib中(以后scroll

    View的子控件都添加到该view中)2:设置view的约束,上下左右都为0,在设置此时该view的高度,此时该view的高度就为scrollView的contentSize 3:在设置控件的竖直滚动,就设置水平居中,水平滚动,就竖直居中 4:在设置xib时,设置父控件的高度等于内部子控件的高度,首先先添加父控件,设置好父控件的约束,在设置子控件的约束,最后来到最左边,删掉父控件的高度约束,再在左边拖线,设置父控件最后一个控件的bottom和父控件的bottom的约束。4:若想设置scrolView上下左右都可以滚动,则添加一个子控件到scrollView,也是scroll唯一的子控件,设置该view上下左右的间距为0,设置宽高,不去设置水平竖直居中就可以了

    #:## 在storyboardxib中给UIScrollView子控件添加约束

    - 给添加一个UIView类型的子控件A(这将是UIScrollView唯一的一个子控件)

    - 设置A距离UIScrollView上下左右间距都为0

    - 往A中再添加其他子控件

    ![](../Images/Snip20151109_228.png)

    - 上下滚动(垂直滚动)

        - 设置A的高度(这个高度就是UIScrollView的内容高度: contentSize.height)

        ![](../Images/Snip20151109_202.png)

        - 设置A在UIScrollView中左右居中(水平居中)

        ![](../Images/Snip20151109_203.png)

    - 左右滚动(水平滚动)

        - 设置A的宽度(这个宽度就是UIScrollView的内容宽度: contentSize.width)

        ![](../Images/Snip20151109_231.png)

        - 设置A在UIScrollView中上下居中(垂直居中)

        ![](../Images/Snip20151109_230.png)

    - 上下左右滚动(水平垂直滚动)

        - 设置A的宽度(这个宽度就是UIScrollView的内容宽度: contentSize.width)

        - 设置A的高度(这个高度就是UIScrollView的内容高度: contentSize.height)

        ![](../Images/Snip20151109_232.png)

        ![](../Images/Snip20151109_229.png)

     10:实现对系统控件的监听:查看系统控件的API中或是父类的API中,1:代理 2:继承UIControl 的addTarget 3:系统通知  4:kvo,主要是监听的是属性的改变 5:利用系统内部的某些机制,重写系统的方法也可以实现监听系统的行为

     11:assign 和 weak的区别:

    1:报错EXC_BAD_Access 野指针错误,就是说访问了一个内存不存在,已经销毁了的对象,会报此错误  2:assin 和weak的区别:1:assin用于修饰基本数据类型   strong和weak用来修饰对象,2:两者的本质区别:

    @property (nonatomic, assign) XMGDog *dog;  // XMGDog *__unsafe_unretained _dog;

    __unsafe_unretained的特点:

    1.不是强引用, 不能保住OC对象的命

    2.如果引用的OC对象销毁了, 指针并不会被自动清空, 依然指向销毁的对象(很容易产生野指针错误: EXC_BAD_ACCESS)__weak的特点:

    @property (nonatomic, weak) XMGDog *dog;  // XMGDog * _Nullable __weak _dog;

    1.不是强引用, 不能保住OC对象的命

    2.如果引用的OC对象销毁了, 指针会被自动清空(变为nil), 不再指向销毁的对象(永远不会产生野指针错误)

    ```

    - 用途

        - assign一般用在基本数据类型上面, 比如intdouble等

        - weak一般用在代理对象上面, 或者用来解决循环强引用的问题

    - 本质区别

        - 速度比较: __unsafe_unretained > __weak

    12:## 监听UITextField的获得焦点和失去焦点事件:

    1:继承UIControl的addTarget:(自己也可以监听自己,addTarget)

    [textField addTarget:target action:@selector(editingDidBegin) forControlEvents:UIControlEventEditingDidBegin];

    [textField addTarget:target action:@selector(editingDidEnd) forControlEvents:UIControlEventEditingDidEnd];

    UIControlEventEditingDidBegin

    1.开始编辑

    2.获得焦点

    3.弹出键盘

    UIControlEventEditingDidEnd

    1.结束编辑

    2.失去焦点

    3.退下键盘

    ```

    UIControlEventEditingDidChange

    文字发生改变的时候

    2:系统控件的代理:(自己成为自己的代理,监听自己的行为,不建议自己成为自己的代理,因为如果在外部也设置了代理,则有可能内部自己监听自己的代理就被外部覆盖掉了,而addTarget则可以去添加多个监听器。add可以无限添加,而set的set方法,只能设置一个)

    - delegate

    ```objc

    textField.delegate = self;

    #pragma mark - <UITextFieldDelegate>

    - (void)textFieldDidBeginEditing:(UITextField *)textField

    {

    }

    - (void)textFieldDidEndEditing:(UITextField *)textField

    {

    }

    ```

    3:系统的通知:

    [textField addTarget:self action:@selector(test) forControlEvents:UIControlEventEditingDidBegin | UIControlEventEditingChanged];

    ```

    - 通知:注册观察者,实现通知方法,dealloc中移除观察者;其中addObserver:注册观察这时,object参数为谁发出的通知,一般传nil,表示只要接收到发出的这个通知就会调用此方法,不管是谁发出的通知。若不是传的nil,则只有后面发出的通知才会调用通知的方法

     ```objc

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditing) name:UITextFieldTextDidBeginEditingNotification object:textField];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing) name:UITextFieldTextDidEndEditingNotification object:textField];

    - (void)dealloc

    {

        [[NSNotificationCenter defaultCenter] removeObserver:self];

    }

    - (void)beginEditing

    {

    }

    - (void)endEditing

    {

    }

    ```

    使用block监听通知:

     ## 通知相关的补充

    ### 使用block监听通知

    1:@property(nonatomic,strong) id  observer;//必须先强引用通知

     2:返回值为观察者,// object对象发出了名字为name的通知, 就在queue队列中执行block

    self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[[NSOperationQueue alloc] init] usingBlock:^(NSNotification * _Nonnull note) {

        // 一旦监听到通知, 就会执行这个block中的代码

    }];

    //3:最后在dealloc中移除监听

    [[NSNotificationCenter defaultCenter] removeObserver:self.observer];

    ```

    ### 其他

    ```objc

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        // 因为是在子线程注册了通知监听器, 所以beginEditing和endEditing会在子线程中执行

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditing) name:UITextFieldTextDidBeginEditingNotification object:self];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing) name:UITextFieldTextDidEndEditingNotification object:self];

    });

     ### 一次性通知(监听1次后就不再监听)

    ```objc

    id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[[NSOperationQueue alloc] init] usingBlock:^(NSNotification * _Nonnull note) {

      // 移除通知

     [[NSNotificationCenter defaultCenter] removeObserver:observer];

    }];

    当对象的类型不能确定的时候,就用id去修饰此对象

    利用系统内部的某些机制重写系统的方法实现监听:可以重写系统的方法(不要忘记调用super的方法),来实现监听,系统的点语法就包括了set方法和get方法,set方法赋值结束后,可以重新调用get方法来获得该值,也可以重写系统的某些方法,点语法的set方法,get方法,或是直接去调用的方法。重写setfont 实现字体的设置,self.font获得字体,重写becomeFirstResponder等实现textfield的开始编辑光标聚焦,键盘弹出的监听

     - 重写UITextField的`becomeFirstResponder`和`resignFirstResponder`方法

    ```objc

    /**

     *  调用时刻 : 成为第一响应者(开始编辑弹出键盘获得焦点)

     */

    - (BOOL)becomeFirstResponder

    {

        return [super becomeFirstResponder];

    }

    /**

     *  调用时刻 : 不做第一响应者(结束编辑退出键盘失去焦点)

     */

    - (BOOL)resignFirstResponder

    {

        return [super resignFirstResponder];

    }

    ```















  • 相关阅读:
    App更新之dialog数字进度条
    Android app启动是出现白屏或者黑屏如何解决?
    Tensorflow报错:AttributeError: module 'tensorflow._api.v1.io' has no attribute 'gfile'
    《Python深度学习》第三章阅读笔记
    在Ubuntu 18.04上配置CPU深度学习环境
    《Python深度学习》第二章阅读笔记
    《Python深度学习》第一章阅读笔记
    POJ 1118 Lining Up
    蓝桥杯-地宫取宝(动态规划)
    洛谷P2280[HNOI2003] 激光炸弹(二维前缀和)
  • 原文地址:https://www.cnblogs.com/cqb-learner/p/5891071.html
Copyright © 2020-2023  润新知