美文网首页
iOS开发中的一些技巧

iOS开发中的一些技巧

作者: XiaoWhite | 来源:发表于2017-05-23 19:58 被阅读87次

    声明:文章内容中所有涉及的东西,有一些是在网上查找的,有一些是个人在开发中摸索出来的,如果部分内容涉及到了侵权问题,请及时联系我,我会将其注明引用或删除

    1、Why doesn't UIScrollView/UITableview respond to taps on the status bar, and scroll to the top?

    StackOverflow
    This can occur when there are multiple instances of UIScrollView (or a subclass of UIScrollView, such as UITableView) with the scrollsToTop property set to YES on the same view, such as when a UIScrollView is added as a subview to a UIScrollView. Make sure that the scrollsToTop property of only one scroll view is set to YES. The correct UIScrollView should respond to tap events on the status bar after.
    当你把一个 UIScrollView 或者 它的子类的对象(UITableView,UITextView, UICollectionView),作为子视图添加到一个 UIScrollView 中时,必须将其 scrollsToTop 设置为 NO,只保留父视图 scrollView 的 scrollsToTop属性为 YES,这样才能在点击 statusBar 时,scrollView 能够响应。

    2、获取图片类型

    If you have NSData for the image file, then you can guess at the content type by looking at the first byte:

    OC版本

    + (NSString *)contentTypeForImageData:(NSData *)data {
        uint8_t c;
        [data getBytes:&c length:1];
        
        switch (c) {
            case 0xFF:
                return @"image/jpeg";
            case 0x89:
                return @"image/png";
            case 0x47:
                return @"image/gif";
            case 0x49:
            case 0x4D:
                return @"image/tiff";
        }
        return nil;
    }
    

    Swift版本

    /**
         根据 imageData 获取图片的格式
         */
        fileprivate func imageType(_ imageData: Data) -> String {
            
            var c: UInt8 = 0x00
            (imageData as NSData).getBytes(&c, length: 1)
            
            switch c {
            case 0xFF:
                return "image/jpeg"
            case 0x89:
                return "image/png"
            case 0x47:
                return "image/gif"
            case 0x49,0x4D:
                return "image/tiff"
            default: return ""
            }
        }
    

    3、给 TableView 添加系统自带的 UIRefreshControl

    let tableView = UITableView(frame:UIScreen.mainScreen().bounds)
    
    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(refresh),forControlEvents: .ValueChanged)
    tableView.addSubview(refreshControl)
    
    view.addSubview(tableView)
    

    **iOS 10 ** 中,UIScrollView 自带一个 refreshControl 属性,可直接使用

    4、Xcode中使用 #ifdef

    (1) 首先在 Xcode 中配置宏


    Xcode 配置.png

    (2) 在代码中使用

    // 如上图,创建了三个 target,就可以分别在各自的 target 里面,定义一个宏,用来标识自已,
    // 在代码中使用的时候,能过判断宏来取对应的数据或赋值
    // 比如上面三个 target 的名字分别为 Test_Prod, Test_UAT, Test_Dev
    // 其实是一个项目,创建了多个 target,分别对应了 生产、测试和开发三个环境
    // 在各自的 target 里面定义 TEST_PROD, TEST_UAT, TEST_DEV
    
    #ifdef TEST_PROD        
        plistPath = [[NSBundle mainBundle] pathForResource:@"One_Config" ofType:@"plist"];
    #elif defined TEST_UAT        
        plistPath = [[NSBundle mainBundle] pathForResource:@"Two_Config" ofType:@"plist"];
    #elif defined TEST_DEV        
        plistPath = [[NSBundle mainBundle] pathForResource:@"Three_Config" ofType:@"plist"];
    #else        
        plistPath = [[NSBundle mainBundle] pathForResource:@"Four_Config" ofType:@"plist"];
    #endif
    

    如何创建多个 target ,在 第11条 可以找到

    5、CALayer 中 position 和 anchorPoint 的关系

    func test() {
        
        // position 坐标是 anchorPoint 在父 layer 上的位置
        // anchorPoint (0,0) 代表左上角,(1,1) 代表右下角,默认是 (0.5,0.5) (iOS 和 Mac OS 系统中原点位置是不一样的,下面有解释)
        // position 默认是 (layer.width * 0.5,layer.height * 0.5)
        
        
        let redView = UIView(frame: CGRect(x: 50, y: 50, width: 200, height: 200))
        redView.backgroundColor = UIColor.red
        
        
        let yellowLayer = CALayer()
        yellowLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
        yellowLayer.backgroundColor = UIColor.yellow.cgColor
        
        print("before position = \(yellowLayer.position)")
        
        print("before anchorPoint = \(yellowLayer.anchorPoint)")
        
        redView.layer.addSublayer(yellowLayer)
        
        // anchorPoint 不变,position 变
        yellowLayer.position = CGPoint(x: 0, y: 0)
        
        
        // anchorPoint 变,position 不变
        //yellowLayer.anchorPoint = CGPoint(x: 0, y: 0)    
        yellowLayer.anchorPoint = CGPoint(x: 0, y: 0)
        
        
        print("after position = \(yellowLayer.position)")
        
        print("after anchorPoint = \(yellowLayer.anchorPoint)")
        
        
        view.addSubview(redView);
    }
    

    在 iOS 系统中,Layer 的 anchorPoint 所在的坐标系的原点为左上角,在 OS 系统中,原点是左下角,可在 CoreAnimationGuide 中查看

    Unit Coordinate Systems.png
    Snip20180604_2.png

    6、隐藏导航栏返回按钮上的文字,只保留箭头;自定义返回箭头图片

    方法一:(亲测有效)

    [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(-60,-60) forBarMetrics:UIBarMetricsDefault];
    
    

    方法二:

    Try 
    self.navigationItem.backBarButtonItem.hidden = YES; 
    or
    self.navigationItem.backBarButtonItem = nil;
    or
    self.navigationItem.hidesBackButton = YES;
    Place one of these either in viewWillAppear:, viewWillLoad or viewDidAppear: of the class you want to get rid of the back button in.
    

    设置返回箭头图片

    // 设置返回 icon
    UIImage *backButtonIcon = [UIImage imageNamed:@"BackItem"];
    self.navigationController.navigationBar.backIndicatorImage = backButtonIcon;
    self.navigationController.navigationBar.backIndicatorTransitionMaskImage = backButtonIcon;
    

    7、URL编码内容、还原内容

    在进行网络请求时,如果 URL 里面有中文,就需要进行编码,然后再去使用

    编码时注意选择对应的 NSCharacterSet ,否则编码出来的东西可能会出现不一致的情况

    // 使用这个编码时注意要用 URLQueryAllowedCharacterSet ,否则出来的内容,与接收到的有一些不一致
    NSString *encodedContents2 = [contents stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        
    NSLog(@"encodedContents2 = %@",encodedContents2);
        
    // 使用这个方法,编码出来的内容和接收到的一致,但是这个 API 已经被 deprecated
    NSString *encodedContents3 = [contents stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        
    NSLog(@"encodedContents3 = %@",encodedContents3);
    

    如果接收到的 URL 里面是编码过的内容,可以通过 string 的属性直接获取原始内容

    NSString *contents = originalContents.stringByRemovingPercentEncoding;
    

    8、UITableView 在 Group style 下设置 header/footer 高度

    (1)如果要去掉第一个cell 上面的空白的话,需要给 tableView 设置一个 tableHeaderView,把这个 view 的高度调成一个非常小的数

    self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, SCREEN_WIDTH, 10.0f)];
    

    (2)设置 header/footer 的高度
    有两种方法:
    方法一:直接设置 tableView 的属性

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

    方法二:在代理里面设置
    这个时候需要注意,如果要设置 0 的话,直接 return 0 是没有效果的,也是需要返回一个很小的数,这种方法也可以去除第一个 cell 上面的空白
    注意: 如果只要 header 的高度的话,一定要把 footer 设置成 0.000001 ,以免误以为设置的 header 的高度没起作用

    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
         return 10.0;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
        return 0.01;
    }
    

    9、自定义了 leftBarButtonItem 之后,边缘手势失效

    self.navigationController.interactivePopGestureRecognizer.delegate = (id)self;
    

    10、如何让边缘手势失效

    在iOS7以后,如果是用NavgationController推出来的界面,这个界面都有边缘手势侧滑效果,想让界面不响应这个边缘手势只需要一行代码:(一但调用,所有地方都会失效)

    //关闭边缘手势,这个值默认是YES
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    

    11、在一个项目里面创建多个 Target

    (1) 在原来的 Target 上面右键,Duplicate

    1.png

    (2) Xcode 会创建一个新的 Target 以及与它相对应的 xxx-info.plist 文件

    1.png

    (3)修改新的 Target 的名字和它对应 info.plist 文件的名字

    3.png

    (4)在新的 Target 的 BuildSetting 中配置对应的 info.plist文件路径,可以写完整路径:$(SRCROOT)/TargetTest-Two-Info.plist

    $(SRCROOT): 定位到工程所在的目录,与 TargetTest.xcodeproj 同一等级的目录下

    4.png

    12、关于导航栏半透明的设置

    extendedLayoutIncludesOpaqueBars:这个属性表示,是否将 controller 的 rootView(即 self.view) 扩展到不透明的 bar 下面,默认为 NO;
    navigationBar 默认是半透明的(translucent = YES),
    self.edgesForExtendedLayout 默认是 UIRectEdgeAll

    所以默认情况下controllerrootView 会被扩展到半透明的 navigationBar 下面,即 self.view 的大小和屏幕大小一样;

    默认情况

    当我们将 navigationBar.translucent 设置为 NO 时(不透明),由于 extendedLayoutIncludesOpaqueBars 默认为 NO,不扩展到不透明的 bar 下面,所以这个时候,controller 的 rootView 顶部是从 navigationBar 的底部开始的;

    导航栏不透明

    如果将 extendedLayoutIncludesOpaqueBars 设置为 YES,那么 rootView 还是会被扩展,大小与屏幕大小一样

    导航栏不透明

    相关文章

      网友评论

          本文标题:iOS开发中的一些技巧

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