美文网首页
iOS 项目小知识点

iOS 项目小知识点

作者: MRNAN_ | 来源:发表于2017-02-05 12:06 被阅读45次

    自定义控件

    在- (instancetype)initWithFrame:(CGRect)frame
    里自定义控件
    在- (void)layoutSubviews 里布局控件

    名字叫attributes并且是NSDictionary *类型的参数,它的key一般都有以下规律
     1.iOS7开始
     1> 所有的key都来源于: NSAttributedString.h
     2> 格式基本都是:NS***AttributeName 
     2.iOS7之前
     1> 所有的key都来源于: UIStringDrawing.h
     2> 格式基本都是:UITextAttribute***
    
       NSString * title = [button currentTitle]; // 获取按钮当前title文字
       CGSize size = [title sizeWithAttributes:@{NSFontAttributeName:button.titleLabel.font}];//根据字体计算大小
     _titleUnderLine.backgroundColor = [titleButton titleColorForState:UIControlStateSelected]; //根据按钮title 颜色设置下划线颜色
    
    

    cell分割线顶头操作

    1.第一种方法,利用系统的属性去设置

    项目中经常会有些需求是cell 的分割线顶头,而系统默认的是前面有一定的间距,其实这是由一个separatorInset 属性造成的(iOS7以后出的),通过打印:

    - (void)viewDidAppear:(BOOL)animated
    {
        NXLog(@"margin:%@",NSStringFromUIEdgeInsets(self.tableView.separatorInset));
    }
    
    打印结果:
    margin:{0, 15, 0, 0}   //可以看出来系统默认有一个15的偏移量
    

    将该属性设置为空,现在tableView里面设置:

     self.tableView.separatorInset = UIEdgeInsetsZero; //分隔线顶头,这个只是设置tableView 顶头,还需要在cell里设置cell的顶头
    通过这一步设置发现分割线比之前左移了不少,但是还没顶到头,这里就判断是cell自身的原因
    

    同时在cell 里面进行设置:

    self.separatorInset = UIEdgeInsetsZero;//cell分割线顶头
    

    这时候运行再看结果,已经OK顶到头。

    Paste_Image.png

    tableView底层实现

    1.tableView 先把所有cell 的尺寸计算好,保存到一个数组里。
    2.当cell 要显示的时候就拿到这个cell 去设置frame : cell.frame = frames[row]。

    2.第二种方法,重写cell 的setFrame,可以随意设置cell 的间距,比较万能。

    主要思路:主要就是利用了上面的tableView 的实现原理。
    1.首先设置tableView的背景色为分割线的颜色。
    2.禁掉系统的分割线
    3.在cell类中重写setFrame 方法。

     self.tableView.backgroundColor = NXColor(220, 220, 221);
     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    
    //在自定义的cell类中:
    - (void)setFrame:(CGRect)frame
    {
        NXLog(@"cellFrame:%@",NSStringFromCGRect(frame));
        //因为之前的frame 都是计算好的,这是在要显示的时候去设置一下,所以这里只去将高度减1,不会影响到其他尺寸
        frame.size.height -=1;  // 如果想要间距更大的话可以 -=10 等,随意这种方法比较万能
        //这个才是系统真正的设置frame。重写了这个方法会将系统的frame清空,所以需要调用这个
        [super setFrame:frame];
    }
    

    屏幕适配

    1.一个view从Xib 加载,需不需要重新固定一下尺寸? 这个是一定得需要的,比较保险。
    2.一般添加xib view的时候是在viewDidLoad 里面加载,但是设置尺寸frame 最好在viewDidLayoutSubViews 里面去设置。因为viewDidLoad 并不会去布局frame ,只是拿到xib 设置的大小属性,只有在 viewDidLayoutSubViews 里才会去根据布局去确定控件的最终尺寸(不过添加view 的操作不能放在这里,因为这个方法会调用多次)

    🌰:
    - (void)viewDidLoad {
        [super viewDidLoad];
        UIView * loginView = [NXLoginRegistView loginView];
        [self.middleView addSubview:loginView];
        UIView * registView = [NXLoginRegistView registView];
        [self.middleView addSubview:registView];
        UIView * fastLogin = [NXFastLoginView fastLoginView];
        [self.bottomView addSubview:fastLogin];
    }
    
    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];
        //在这里面设置尺寸
        UIView * loginView = [self.middleView subviews][0];
        loginView.frame = CGRectMake(0, 0, self.middleView.frame.size.width * 0.5, self.middleView.frame.size.height);
        UIView * registView = [self.middleView subviews][1];
        registView.frame = CGRectMake(self.middleView.frame.size.width * 0.5, 0, self.middleView.frame.size.width * 0.5, self.middleView.frame.size.height);
        UIView * fastLogin = [self.bottomView subviews][0];
        fastLogin.frame = CGRectMake(0, 0, self.bottomView.frame.size.width, self.bottomView.frame.size.height);
    }
    
    
    

    从Xib加载的view 设置动画

    是通过操作约束去设置,比如要修改x值产生动画就找到x的约束拖线添到类文件中成为属性,然后对该属性进行操作,在设置动画时,必须加上这句 :

            [self.view layoutIfNeeded]; //这句话很重要,只有重新布局才会产生动画效果,否则没有动画效果
    
    

    例如

    [UIView animateWithDuration:1 animations:^{
            self.testViewWidthConstraint.constant = 200;
            [self.view layoutIfNeeded]; //这句话很重要,只有重新布局才会产生动画效果,否则没有动画效果
    }];
    

    一个xib文件可以管理多个view

    重写button 的布局

    这个在项目中也很常见,默认的按钮布局是左右布局,即左边imageView + 右边label 。而好多项目中需要的是上下布局,所以需要自定义button,重新布局。这里在layoutSubViews 方法里面进行,因为在这个方法里面所有的控件尺寸都已经是计算好的,我们就不需要重新去计算,只要改一下布局就可以。

    🌰:
    - (void)layoutSubviews
    {
        [super layoutSubviews];
        self.imageView.nx_y = 0;
        self.imageView.nx_centerX = self.nx_centerX;
        self.titleLabel.nx_y = self.nx_height - self.titleLabel.nx_height;
        self.titleLabel.nx_centerX = self.nx_centerX;
    }
    

    自定义tabBar的问题

    项目中需要定制tabBar 的时候需要用到自定义tabBar,这里需要注意的是不能直接通过如下的赋值语法进行替换:

    🌰:
       NXTabBar * nTabBar = [[NXTabBar alloc]init];
       self.tabBar = nTabBar;
    这样替换的话是没有效果的,需要用KVC 的形式进行替换:
       
     [self setValue:nTabBar forKey:@"tabBar"];
    

    iOS类私有属性的访问和修改

    http://www.jianshu.com/p/a667f0ce9573

    iOS 类别中添加属性(属性和实例变量的区别)

    【转】iOS中属性与成员变量的区别
    iOS Category中添加属性和成员变量的区别

    通过category 和 runtime 设置textField 的 placehold 的颜色

    项目中经常会用到textField ,比如登录注册等。默认的光标是蓝色,而且placeholder的文字颜色也是灰的,不会变化。有时候项目会需求点击后光标为白色,同时placeholder 的文字高亮为白色(或其他颜色)。通过头文件一级一级往上查找,找到了一个如下属性:

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

    利用这个属性,用如下方法进行颜色修改:

     //第一个参数: 需要被设置属性的字符串
     //第二个参数: 需要设置的属性
        self.attributedPlaceholder = [[NSAttributedString alloc]initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];
    

    这个方法虽然达到效果了,但是比较麻烦,通过如下图的方式,随便写一个textField ,然后打上短点,我们可以看到在textField 内部有placeholderLabel的属性,所以可以尝试通过对该属性进行操作,直接修改颜色。不过通过下面的调试框可以看到这是一个私有属性。想要对私有属性进行访问和修改可以使用kvc 或者 runtime ,这里使用kvc ,新建一个类别,添加属性placeholderColor,在set 方法里面去进行设置:

    🌰:
    h 文件
    #import <UIKit/UIKit.h>
    
    @interface UITextField (NXTextField)
    @property (nonatomic ,strong)UIColor *placeholdColor;
    @end
    
    m 文件
    - (void)setPlaceholdColor:(UIColor *)placeholdColor
    {
        //根据判断,textField 内部的 placehold  是一个label 的标签
        
        UILabel * placeholderLabel = [self valueForKey:@"placeholderLabel"];
        placeholderLabel.textColor = placeholdColor;
        
    }
    - (UIColor *)placeholdColor{
        return nil;  // 暂时先不用,返回一个nil ,去掉系统的警告⚠️
    }
    
    

    然后可以在需要设置的地方引入category 的头文件,通过如下方式即可设置颜色:

        self.placeholdColor = [UIColor lightGrayColor];
    
    Paste_Image.png

    通过上面category 的方式基本可以满足需求,但是如果textField 如下设置的时候就会出现无效:

    // 这样设置是可以的:
      self.placeholder = @"44444";
      self.placeholdColor = [UIColor lightGrayColor];
    
    //将上面的换个顺序执行,就会无效:
     self.placeholdColor = [UIColor lightGrayColor];
     self.placeholder = @"44444";
    
    //这是因为之前没有设置placeholder文字,设置颜色的时候通过断点可以看到,此时获取不到placeholderLabel,所以导致设置颜色无效。
    

    解决这个问题就需要用到runtime
    1.先将 placeholderColor 保存起来
    2.在设置placeholder 的时候再取出来设置颜色

    - (void)setPlaceholdColor:(UIColor *)placeholdColor
    {
        //先将placeholdColor 存起来
        //参数一:给哪个对象添加成员属性
        //参数二:成员属性的名字
        //参数三:成员属性的值
        objc_setAssociatedObject(self, @"placeholdColor", placeholdColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        //根据判断,textField 内部的 placehold  是一个label 的标签
        
        UILabel * placeholderLabel = [self valueForKey:@"placeholderLabel"];
        placeholderLabel.textColor = placeholdColor;
        
    }
    - (UIColor *)placeholdColor{
        return objc_getAssociatedObject(self, @"placeholdColor");
    }
    
    //自顶一个setPlaceholder方法,在内部1.先设置文字。 2.设置颜色
    - (void)setNX_Placeholder:(NSString *)placeholder
    {
        self.placeholder = placeholder;
        self.placeholdColor = self.placeholdColor;
    }
    

    上面方法有个缺点就是每次设置placeholder文字还得去调用

        [self setNX_Placeholder:@"hhhh"];
    

    所以想要直接通过: ** self.placeholder = @"hhhh"; 去设置,就需要用到方法交换。因为交换只需要做一次操作,所以,放到+(void)load**方法里去操作,在category文件中加入:

    + (void)load{
        Method setPlaceholder = class_getInstanceMethod(self, @selector(setPlaceholder:));
        Method setNx_Placeholder = class_getInstanceMethod(self, @selector(setNX_Placeholder:));
        method_exchangeImplementations(setPlaceholder, setNx_Placeholder);
    }
    

    计算总行数的万能公式

    row = (count -1 ) / column +1;

    
    #tableView  调整cell 间距
    >用storyBoard 拖出来的cell 默认显示的是如下图的间距(因为要使用到静态单元格,所以用到storyBoard,一般情况下用xib最好)
    ![Paste_Image.png](https://img.haomeiwen.com/i972822/1b72dbea6ce3c123.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    这里用的是分组style,所以可以通过设置  
    

    self.tableView.sectionFooterHeight = 0;
    self.tableView.sectionHeaderHeight = 0;

    得到如下效果:
    
    ![Paste_Image.png](https://img.haomeiwen.com/i972822/13edc8b059e545ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    可以看到每个分组之间的间距已经没了,但是第一个cell 距离顶部还是有好大一部分距离,这里判断可能是tableView 的间距,通过下面打印
    
    ![Paste_Image.png](https://img.haomeiwen.com/i972822/ae86d387b8e4f8e8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    可以看到tableView 距离顶部确实有64 的偏移量,但是这个刚好是空出导航栏的高度,所以排除是tableView 的问题,接下来就判断是cell 的问题,通过下面打印
    
    ![Paste_Image.png](https://img.haomeiwen.com/i972822/bc281de06bbc0996.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    可以看到分组内部第一个cell 的Y 值默认是35 ,那么这里可以在viewDidLoad 方法里进行如下调整就可以(这里需要间隔为10)
    

    self.tableView.sectionFooterHeight = 0;
    self.tableView.sectionHeaderHeight = 10;
    self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0);

    #跳转到网页
    >1.`Safari  openURL`  自带很多功能:进度条,刷新,前进,倒退等功能。但是需要跳出到当前应用。
    2.`UIWebView`  在当前应用打开网页,并且带有Safari(自己实现),不能实现进度条。
    3.`SFSafariViewController`   专门用来显示网页,既可以在当前应用显示网页,又可以有Safari的功能。iOS9以后才可以用。
    4.WKWebView
    #判断view 是否被加载
    

    随便一个都可以:
    UIViewController * vc = self.childViewControllers[button.tag];
    if (vc.isViewLoaded) {//如果已经被加载过就不重复加载(加载view 的时候会调用 viewDidLoad)
    return ;
    }
    UIView * view = vc.view;
    if (view.superview) { // 如果有父view ,说明已经被添加过
    return;
    }
    if (view.window) { //如果有容器,说明已经被添加过
    return;
    }

    
    #  一些全局常量,尽量使用extern来引用,其次再选择考虑Macro
    >[iOS const的使用](http://www.cnblogs.com/oumygade/p/4316024.html)
    [关于全局常量的定义](http://www.jianshu.com/p/ed2dfbca6e73)
    
    
    #xib cell 拖线报错: Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x8a4b500> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key 
    
    >如下图,我已开始在File`s Owner里也设置了class是NXTopicCell,所以一直出错,这里吧他清空,设置下面的Topic Cell 的class如下就可以
    ![Paste_Image.png](https://img.haomeiwen.com/i972822/ab6ca235996cb993.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    >xib拖的UILabel 没有自动换行:设置约束时不要给定高度就可以自动换行了。
    
    #在heightForRowAtIndexPath获取cell 崩溃
    http://www.jianshu.com/p/3da539540d21
    >在网上看到有人是这么获取:
    

    NXTopicCell * cell = (NXTopicCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];

    试了下好像是可以。
    
    
    >好像xib  里设置的高度是定死的,不会根据不同屏幕去重新计算高度。
    
    ##退出键盘
    
    >1.监听scrollView实时滚动代理方法调用[self.view endEditing:YES]或者[self.textField resignFirstResponse];
    2.touchBegin方法里,调用[self.view endEditing:YES]或者[self.textField resignFirstResponse];
    
    ##父View添加手势,子View不要去响应父View点击事件
    [iOS 点击子视图不让其响应父视图手势](http://www.it610.com/article/4821007.htm)
    >在做这样一个界面的时候
    
    ![Paste_Image.png](https://img.haomeiwen.com/i972822/719483b12316733c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    >背景的蒙版层是一个UIView,按钮的列表View添加到背景的蒙版View上。在蒙版层添加一个手势,点击dismiss掉这个界面和蒙版。但是遇到问题就是在点击按钮列表的View的时候也出发了单击手势。这个好像是系统默认的,参考事件响应链。为了避免这种效果,在手势触发事件中可以判断当前点击事件是否在父View上,如果是子View上则不去做操作,点击在父View上才去做dismiss的操作。代码如下:
    
    
    • (void)dismissMoreActionView:(UITapGestureRecognizer *)tap
      {
      //根绝tag获取子view
      UIView *subView = [self viewWithTag:100];

      /*
      BOOL contains = CGRectContainsPoint(CGRect rect, CGPoint point);
      判断一个CGRect是否包含再另一个CGRect里面,常用与测试给定的对象之间是否又重叠

      • (CGPoint)locationInView:(UIView *)view:
        该函数返回一个CGPoint类型的值,表示触摸在view这个视图上的位置,这里返回的位置是针对view的坐标
        */
        // 判断手势点击的位置是不是包含在子视图上
        if (!CGRectContainsPoint(subView.frame, [tap locationInView:self])) {
        [self removeFromSuperview];
        }
        }
    
    ----------------------
    ## 调整导航栏leftBarButtonItem 和 rightBarbuttonItem 的偏移量
    [ 如何调整导航条上的leftBarButtonItem和rightBarButtonItem的位置](http://yikuwang.blog.51cto.com/6186082/1696156)
    
    > ####重点:
    这里需要提到BarButtonSystemItem的样式- UIBarButtonSystemItemFixedSpace
    我不多说 请看官方解释:Blank space to add between other items. Only the [width](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIBarButtonItem_Class/index.html#//apple_ref/occ/instp/UIBarButtonItem/width) property is used when this value is set.  反正我是看不懂 。再来说说negativeSpacer.width = 0 表示leftBarButtonItem的x离屏幕的左边还有15像素 同样表示rightBarButtonItem的CGRectGetMaxX()离屏幕的右边还有15像素 那么好像我们就可以通过negativeSpacer.width来调整leftBarButtonItem的位置。搞了老半天原来就是得靠这家伙。但有一点:negativeSpacer.width赋值负数对于leftBarButtonItem来说是左移多少像素 对于rightBarButtonItem来说是右移多少像素  反之亦然.
    
    我这里想要设置右边的item 右移一点,因为默认的太偏左了:
    

    UIButton * buyBtn = [[UIButton alloc]init];

     buyBtn.frame = CGRectMake(0, 0, 80, 40);
     
     buyBtn.backgroundColor = [UIColor orangeColor];
     
     [buyBtn setTitle:@"马上选购" forState:UIControlStateNormal];
     
     buyBtn.titleLabel.font = [UIFont systemFontOfSize:15];
          
     [buyBtn addTarget:self action:@selector(buyItemAction) forControlEvents:UIControlEventTouchUpInside];
     
     UIBarButtonItem * buyItem = [[UIBarButtonItem alloc]initWithCustomView:buyBtn];
     
     UIBarButtonItem * space = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
     space.width = -10;
     
     self.navigationItem.rightBarButtonItems = @[space,buyItem];
    
    
    ##动态修改UIButton的title 的时候字体闪烁的问题:
     [UIButton-system类型 动态改变title 显示文字时闪动(解决方案)](http://blog.csdn.net/a330416020/article/details/41648787)
    *******************
    ##assign 修饰代理导致野指针的问题
    >在下面方法中调用了代理,崩溃指向这里显示野指针的错误,猜测是由于代理被释放而去调用产生的问题。点进去看到之前代理修饰用的是assign 修饰的,改为weak 后好像是可以了。猜测原因是由于assign 修饰的话 assign是指针赋值,不对引用计数操作,使用之后如果没有置为nil,可能就会产生野指针;而weak一旦不进行使用后,永远不会使用了,就不会产生野指针。
    
    
    • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
      {
      if ([_delegate respondsToSelector:@selector(numberOfRowsInTableView:Insection:FromView:)])
      {
      NSInteger vRows = [_dataSource numberOfRowsInTableView:tableView Insection:section FromView:self];
      mRowCount = vRows;
      return vRows;
      }
      return 0;
      }
    ##单例问题
    >在使用单例的时候,经常性就是直接写出下面的代码。不过最近在使用的时候会遇到单例导致崩溃的问题。一开始在写 `dispatch_once_t once_token`的时候没有用static 来修饰,后来加上static来修饰就好了。
    
    
    • (instancetype)shareInstance
      {
      static DrawTextView * drawText = nil;

      static dispatch_once_t once_token;

      dispatch_once(&once_token, ^{

        drawText = [[DrawTextView alloc]initWithFrame:CGRectMake(kDeviceW * 0.5- TextLayerWidth * 0.5, kDeviceH * 0.5 - TextLayerHeight * 0.5, TextLayerWidth, TextLayerHeight)];
        drawText.backgroundColor = [UIColor orangeColor];
      

      });
      return drawText;
      }

    
    ##在iPhone5s (10.2系统)拨打电话没有弹框提示,其他手机(10.3)有弹框
    

    // 用这种方法的话会出现上面的问题
    // NSString * phonNum = [NSString stringWithFormat:@"tel://%@",self.footerModel.dav_phone];

     NSString * phonNum = [NSString stringWithFormat:@"telprompt://%@", self.footerModel.dav_phone];
    

    控制器切换从下往上,并且有导航栏:

    可以用CATransition 动画,或者直接用presentModalViewController。
    http://www.cocoachina.com/bbs/read.php?tid=7668

    改变SearchBar 的取消按钮颜色,光标颜色

    http://www.jianshu.com/p/66b5b777f5dc

    DBL_EPSILON和 FLT_EPSILON的用法

    DBL_EPSILON和 FLT_EPSILON主要用于单精度和双精度的比较当中:

    imageimage

    比较方式

    double b = sin(M_PI / 6.0);
    if (fabs(((double)valueint)-value)<=DBL_EPSILON)
        (is int num);
    else
        (is double num)
    

    EPSILON是最小误差。如果整数值减去浮点数值误差低于DBL_EPSILON,则说明该数可以近似看成整数,否则则是浮点数……

    绘制渐变的UIImage

    首先网上找到的是第一种的方法,
    1.先生成一个渐变图层

     CAGradientLayer * gradientLayer = [CAGradientLayer layer];
        CGFloat navigationBarHeight = statusBarRect.size.height +  self.navigationController.navigationBar.frame.size.height;
        gradientLayer.frame = CGRectMake(0, 400, [UIScreen mainScreen].bounds.size.width, navigationBarHeight);
        gradientLayer.colors = @[(id)[UIColor colorWithRed:22/255.0 green:112/255.0 blue:188/255.0 alpha:1].CGColor,(id)[UIColor colorWithRed:30/255.0 green:26/255.0 blue:150/255.0 alpha:1].CGColor];
        gradientLayer.startPoint = CGPointMake(0, 0.5);
        gradientLayer.endPoint = CGPointMake(1, 0.5);
    

    2.通过渐变图层绘制图片:

    - (UIImage *)imageFromLayer:(CALayer *)layer
    {
        UIGraphicsBeginImageContextWithOptions(layer.frame.size, layer.opaque, [UIScreen mainScreen].scale);
        [layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage * outImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return outImage;
    }
    

    但是如上的方法好像并没有生成想要的图片。
    网上找到第二种,可以生成想要的图片:

    /**
     *  获取矩形的渐变色的UIImage(此函数还不够完善)
     *
     *  @param bounds       UIImage的bounds
     *  @param colors       渐变色数组,可以设置两种颜色
     *  @param gradientType 渐变的方式:0---&gt;从上到下   1---&gt;从左到右
     *
     *  @return 渐变色的UIImage
     */
    - (UIImage*)gradientImageWithBounds:(CGRect)bounds andColors:(NSArray*)colors andGradientType:(int)gradientType{
        NSMutableArray *ar = [NSMutableArray array];
        for(UIColor *c in colors) {
            [ar addObject:(id)c.CGColor];
        }
        UIGraphicsBeginImageContextWithOptions(bounds.size, YES, 1);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSaveGState(context);
        CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors lastObject] CGColor]);
        CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)ar, NULL);
        CGPoint start;
        CGPoint end;
        
        switch (gradientType) {
            case 0:
                start = CGPointMake(0.0, 0.0);
                end = CGPointMake(0.0, bounds.size.height);
                break;
            case 1:
                start = CGPointMake(0.0, 0.0);
                end = CGPointMake(bounds.size.width, 0.0);
                break;
        }
        // 线性渐变
        CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        CGGradientRelease(gradient);
        CGContextRestoreGState(context);
        CGColorSpaceRelease(colorSpace);
        UIGraphicsEndImageContext();
        return image;
    }
    

    还有一些其他类似方法,参考如下:iOS实现颜色渐变

    画线控件(支持xib和storyboard)

    自定义一个控件,继承自UIView,.h文件声明属性

    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ADHouseSourceDottedLine : UIView
    @property (nonatomic ,assign)IBInspectable CGFloat  lineWidth;
    @property (nonatomic ,strong)IBInspectable UIColor * lineColor;
    
    @property (nonatomic ,assign)IBInspectable CGFloat  paddingLeft;
    @property (nonatomic ,assign)IBInspectable CGFloat  paddingRight;
    @property (nonatomic ,assign)IBInspectable CGFloat  paddingTop;
    @property (nonatomic ,assign)IBInspectable CGFloat  paddingBottom;
    
    @property (nonatomic ,assign)IBInspectable BOOL  isHorizontal;
    @property (nonatomic ,assign)IBInspectable BOOL  isDash;
    @property (nonatomic ,assign)IBInspectable CGFloat  dashPointWidth;
    @property (nonatomic ,assign)IBInspectable CGFloat  dashSpace;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    

    然后再.m文件里面,@implementation前面用IB_DESIGNABLE修饰。

    #import "ADHouseSourceDottedLine.h"
    IB_DESIGNABLE
    
    @implementation ADHouseSourceDottedLine
    - (void)drawRect:(CGRect)rect
    {
        [super drawRect:rect];
        CGContextRef currentContext = UIGraphicsGetCurrentContext();
        CGFloat bx = 0,by = 0,ex = 0,ey = 0;
        if (_isHorizontal) {
            bx = _paddingLeft;
            by = rect.size.height * 0.5;
            ex = rect.size.width - _paddingRight;
            ey = by;
        }else
        {
            bx = rect.size.width * 0.5;
            by = _paddingTop;
            ex = bx;
            ey = rect.size.height - _paddingBottom;
        }
        // 画中间虚线
    //    CGMutablePathRef path = CGPathCreateMutable();
    //    CGPathMoveToPoint(path, NULL, bx, by);
    //    CGPathAddLineToPoint(path, NULL, ex, ey);
        
        CGContextMoveToPoint(currentContext, bx, by);
        CGContextAddLineToPoint(currentContext, ex, ey);
        // 2、 添加路径到图形上下文
    //    CGContextAddPath(currentContext, path);
        CGContextSetLineWidth(currentContext, _lineWidth / [UIScreen mainScreen].scale);
        CGContextSetStrokeColorWithColor(currentContext, _lineColor.CGColor);
        if (_isDash) {
            CGFloat lengths[] = {_dashPointWidth , _dashSpace};
            CGContextSetLineDash(currentContext, 0, lengths, 2);
        }
        // 4、 绘制图像到指定图形上下文
    //    CGContextDrawPath(currentContext, kCGPathFill);
        CGContextStrokePath(currentContext);
    }
    
    @end
    
    

    参考:# 在OC和Swift中使用IBDesignable/IBInspectable
    Swift 画线控件(支持xib和storyboard)

    相关文章

      网友评论

          本文标题:iOS 项目小知识点

          本文链接:https://www.haomeiwen.com/subject/jpxeittx.html