·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> app软件开发 >> IOS开发 >> 一周随笔--15.11.08

一周随笔--15.11.08

作者:佚名      IOS开发编辑:admin      更新时间:2022-07-23

 

一周新知识点记录(15.11.08)

一、关于hiddenalphaopaque的说明

这3个都是UIView的属性:

hidden:YES或者NO,YES时隐藏UIView对象,并且无法再响应手势(从响应链中移除),其上的子视图也被隐藏且无法响应手势;

alpha:透明度(0~1.0) 0为完全透明,1为不透明。设置为0时,相当于hidden设置为YES,同样无法响应手势。其上的子视图也将完全透明且无法响应手势。

opaque:从名字来看,是否不透明。然而将其设置为NO,意思上看是设置成了透明,然而运行发现仍然是可见的。事实上,这个属性并不是直接设置UIView对象是否透明,它其实用来优化性能的,是给绘图系统提供一个性能优化开关。如果UIView对象完全不透明(即alpha为1),就将其设置成YES。如果UIView对象不完全不透明(alpha不为1),就将其设置成NO,若设置成YES可能会有不可预见的结果。

这样做能够大大提升UIView在绘制时的性能,节省GPU的消耗。具体见http://blog.csdn.net/martin_liang/article/details/40739845


二、Quartz2D补充整理

坐标系

1、Quartz坐标系统默认原点位于左下角,x正轴向右,y正轴向上。  

2、在UIKit中的坐标系统中,原点位于左上角;而Quartz的坐标系统原点位于左下角。在UIView中获得的图形上下文(Graphics Context),系统已经将坐标系统转变成了UIKit的坐标系,是通过将图形上下文的CTM原点平移到左上角,同时将y轴反转(y值乘以-1)得到的。因此在绘制UIView时不需要再对获取到得图形上下文再作坐标系的调整(已经匹配UIView的坐标系了)。    

3、对于位图(bitmap),通过UIGraphicsBeginImageContextWithOptions创建的位图图形上下文(bitmap graphics context),其坐标系统原点是在左上角的,和UIView的图形上下文坐标系统一样,系统已经自动对其进行了转换。  

注意:

(1)只是通过UIGraphicsBeginImageContextWithOptions创建的位图图形上下文坐标系统是自动做了转换的,如果通过CGBitmapContextCreate手动创建位图图形上下文,其坐标系统依旧是Quartz的坐标系统,即以左下角为原点,y轴正方向从下到上。

(2)在drawRect的图形上下文或者UIGraphicsBeginImageContextWithOptions获取的图形上下文中通过CGContextDrawImage方法绘制图片,绘制结果发现图片是倒置的。既然上面说图形上下文已经转换成了UIKit的坐标系,原点在左上角,又怎么会倒置呢?原因在于CGContextDrawImage方法传入的参数CGImage的坐标系是倒置的,避免这种情况可以通过对UIImage调用drawInRect绘制。

(3)必要的时候需要翻转坐标系,方法是 :

    CGContextTranslateCTM(cox, 0, height);

    CGContextScaleCTM(cox, 1.0, -1.0);

 绘制渐变  

可以通过CGShading对象或者CGGradient对象绘制渐变,CGGradient易于重用且用法简单,这里只介绍使用CGGradient绘制渐变。  

主要步骤:  

(1)创建一个CGGradient对象,提供一个颜色空间,一个包含两个或更多颜色组件的数组,一个包含两个或多个位置的数组,和渐变颜色个数。

(2)调用CGContextDrawLinearGradient(轴向)或CGContextDrawRadialGradient(径向)函数并提供一个上下文、一个CGGradient对象、绘制选项和开始结束几何图形来绘制渐变。

(3)当不再需要时释放CGGradient对象。

代码示例:   

      //创建渐变梯度对象方法一
//    size_t numOfLocations = 3; //位置数
//    CGFloat locations[3] = {0, 0.5, 1}; //元素取值0~1 表示位置点到轴线起点的距离与轴线长度的比例
//    CGFloat components[12] = {1.0, 0.5, 0.4, 1.0, 0.8, 0.8, 0.3, 1.0, 0.5,0.5,0.5,1.0}; //颜色组件 元素个数为4的倍数(RGBA*位置数)
//    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, numOfLocations);
//创建渐变梯度对象方法二 CGFloat locations[3] = {0, 0.5, 1}; NSArray *colors = [NSArray arrayWithObjects: (id)[UIColor colorWithRed:0.540 green:1.000 blue:0.814 alpha:1.000].CGColor, (id)[UIColor colorWithRed:1.000 green:0.687 blue:0.695 alpha:1.000].CGColor, (id)[UIColor colorWithRed:0.970 green:1.000 blue:0.488 alpha:1.000].CGColor,nil]; CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,(__bridge CFArrayRef)colors, locations); //绘制轴向渐变 CGContextDrawLinearGradient(cox, gradient, CGPointZero, CGPointMake(rect.size.width, rect.size.height), 0); //绘制径向渐变 // CGContextDrawRadialGradient(cox, gradient, CGPointMake(50, 50), 25, CGPointMake(250, 500), 50, 0);
CGColorSpaceRelease(colorSpace); CGGradientRelease(gradient);

 

透明层  

透明层是一个独立于图形上下文的目标缓存,当需要在一组对象上使用特效时,透明层非常有用,它会把一组对象看成是一个整体来进行特效的绘制。以绘制3个矩形的阴影为例:  

未使用透明层:   

    CGSize myShadowOffset = CGSizeMake (10, -10);
    CGContextSetShadow (cox, myShadowOffset, 5);
CGContextSetRGBFillColor (cox, 0, 1, 0, 1); CGContextFillRect (cox, CGRectMake (20, 20,80,80)); CGContextSetRGBFillColor (cox, 0, 0, 1, 1); CGContextFillRect (cox, CGRectMake (80,80,80,80)); CGContextSetRGBFillColor (cox, 1, 0, 0, 1); CGContextFillRect (cox, CGRectMake (140,140,80,80));

 

使用透明层: 

    CGSize myShadowOffset = CGSizeMake (10, -10);
    CGContextSetShadow (cox, myShadowOffset, 5);
    
    CGContextBeginTransparencyLayer (cox, NULL);  //开启透明层 然后开始绘制
    CGContextSetRGBFillColor (cox, 0, 1, 0, 1);
    CGContextFillRect (cox, CGRectMake (20, 20,80,80));
    CGContextSetRGBFillColor (cox, 0, 0, 1, 1);
    CGContextFillRect (cox, CGRectMake (80,80,80,80));
    CGContextSetRGBFillColor (cox, 1, 0, 0, 1);
    CGContextFillRect (cox, CGRectMake (140,140,80,80));
    CGContextEndTransparencyLayer (cox);  //关闭透明层

 

参考文档:  

[《Quartz 2D编程指南》](http://southpeak.github.io/blog/2014/11/10/quartz-2dbian-cheng-zhi-nan-zhi-%5B?%5D-:gai-lan/)


三、区分分辨率、像素、点、尺寸

分辨率、像素,通常用在屏幕或者图片的说明上,用来表明清晰度。我们通常说这个屏幕的分辨率是多少多少,摄像头像素多少多少,具体什么意思呢?  

以分辨率为320*480的iphone3GS屏幕(一倍屏)为例说明:  

像素:像素是组成图象的最基本单元要素(最小单元),该屏幕长方向上有320个像素,宽方向上有480个像素。320*480约等于15万,就说这个屏幕的像素为15万。一个像素只能显示一种颜色 

分辨率:分辨率是指在长和宽的两个方向上各拥有的像素个数,上面的320*480就是分辨率的表现形式。    

尺寸:尺寸则是屏幕的实际长宽,例如iphone4为3.5英寸,指的时屏幕对角线长度为3.5英寸,1英寸=25.4毫米。  

:点用来构建一个坐标系,它是根据实际情况和需求制定的,是人为设想的,并不是真实存在的。在ios开发中,坐标系的单位长度就是点。在iphone3GS上,一个点包含一个像素,这种屏幕俗称一倍屏;iphone4、4s、iphone5等2倍retina屏上,一个点包含两个像素(这里说的是一维的长度,从二维的角度来讲,一个点包含4个像素,长宽2*2嘛),也就是二倍屏,用@2x表示这种屏幕模式;对于3倍retina的iphone6p和iphone6sp,一个点包含3个像素。开发中在通过点搭建的坐标系中布局界面,方便适配,因为无需再去理会屏幕的分辨率,系统会在显示的时候自动进行适配。

补充:

  • 每个像素大小是不确定的,它由屏幕的尺寸和分辨率决定。
  • 通常所说的像素点就是像素,并不是上面所说的点。
  • 同一张图片或者分辨率相同的图片在不同的屏幕上显示的大小是不一样的,由屏幕像素大小决定。  

A&B->C

C&D->E 

A:屏幕分辨率  

B:屏幕尺寸  

C:屏幕像素大小  

D:图片分辨率  

E:图片在屏幕上的显示尺寸    

  • 若图片分辨率和屏幕分辨率相同,则刚好能完全显示;图片分辨率<屏幕分辨率,图片不能完全显示,若将其拉伸填充整个屏幕,图片清晰度就会下降;图片分辨率>屏幕分辨率,图片显示不下。

参考文章:  

[《像素和分辨率的关系》](http://www.360doc.com/content/13/0630/15/3398926_296570170.shtml)  

[《iOS的APP如何适应iPhone5s/6/6Plus三种屏幕的尺寸》](http://my.oschina.net/u/1049180/blog/362599)


四、iphone屏幕适配规则

有时候运行程序,发现界面上下出现了黑框,这是由于当前程序没有适配iphone5的屏幕导致的。我们知道,iphone5屏幕像素640*1136,比iphone4的640*960在高度上多了176个像素,即88个点,假如程序没有适配iphone5,那么运行在iphone5上的结果就是上下各有高度为44个点的黑边。   

那么系统是怎样得知是否已经适配了iphone5的呢?如果你以为启动图片的作用仅仅是为了在进入app前显示一张图片,那你就错了。它更大的职能其实是在图片显示期间做一些初始化处理,其中包括检查适配情况。这通常比较费时,先出现启动图片,可以使用户觉得系统立即有了响应,减少等待的焦虑感,套路简直深!

对于iphone6而言,如果没有适配iphone5,也没有适配iphone6,那么程序远程时同样上下留黑边。如果适配了iphone5而没有适配iphone6,这时候运行,程序能全屏显示了,但是会发现清晰度不太对,因为iphone5和iphone屏幕长宽比例是一样的,因此只是将iphone5的程序单纯放大了,因此看上去会有点模糊。如果适配了iphone6,就不会存在这种问题了。iphone6s也是同样的道理。而系统识别适配的方法同样是根据是否设置了相应屏幕的启动图来判断。

 目前所有iphone机型共有5中屏幕(竖屏):  

Retina1x(320*480)(iphone3GS之前,现已不用搭理)  

Retina2x(640*960)(iphone4/4s)  

Retina4(640*1136)(iphone5/5s/5c)  

Retina HD4.7(750*1334)(iphone6/6s)  

Retina HD5.5(1242*2208)(iphone6p/6sp) 

参考:  

[《iOS的APP如何适应iPhone5s/6/6Plus三种屏幕的尺寸》](http://my.oschina.net/u/1049180/blog/362599)  


五、启动图设置方法

一、使用LaunchImage  

在工程Targets-App Icons and Launch Images-Launch Image Source中设置启动图资源目录,在Assets.xcassets中的启动图资源文件夹中设置相应屏幕的启动图。这种方法兼容ios7,ios8。

二、使用LauchScreen.xib  

这是Xcode6/iOS8的新功能,也就是说不支持iOS7。所以现在的做法还是使用LaunchImage,将来程序不再需要兼容ios7之后或许LauchScreen.xib能得到广泛应用。  

注意:Xcode默认将LaunchScreen.xib作为启动方式,如果不用LauchScreen.xib设置启动图,将工程Targets-App Icons and Launch Images-Launch Screen File设置为空即可。

[《Launch Screen在iOS7/8中的实现》]http://blog.shiqichan.com/Launch-Screen-in-iOS-7-and-8/ 


六、ios中贝塞尔曲线

UIBezierPath是UIKit框架对于Quartz2D框架CGPathRef的封装,通过它方便绘制,但是也要在绘制图形上下文环境中。  

UIBezierPath有一个CGPathRef类型的属性CGPath,通过它与CG框架实现联系。  

通常UIBezierPath的CGPath属性用在为CAShapeLayer提供渲染的形状。


 

七、 CAShapeLayer

1、CAShapeLayer是一种特殊的层,可以在上面渲染图形。  

2、CAShapeLayer继承自CALayer,可使用CALayer的所有属性。  

3、CAShapeLayer需要和贝塞尔曲线配合使用才有意义,贝塞尔曲线为其提供渲染的图形。  

4、使用CAShapeLayer与贝塞尔曲线可以实现不再view的drawRect方法中画出一些想要的图形。  

 关于CAShapeLayer和drawRect的比较:  

在drawRect中绘制图形调用CoreGraphics框架中的方法,占用CPU,消耗性能大;  

CAShapeLayer属于CoreAnimation框架,通过GPU来渲染图形,节省性能。动画渲染直接提交给GPU,不消耗内存。

用法见Demo http://download.csdn.net/detail/lotheve/9248547


八、CAGradientLayer

1、CAGradientLayer是一种特殊的层,用于渲染渐变效果。  

2、CAGradientLayer继承自CALayer,可使用CALayer所有的属性。  

3、CAGradientLayer是除了在图形上下文绘制渐变效果外的另一种方法,它不需要借助图形上下文,是直接渲染在层上的,因此易于使用。

使用见Demo  http://download.csdn.net/detail/lotheve/9248547


九、CATextLayer

1、CATextLayer是一种特殊的层,可以在上面渲染文本。 

2、通过string属性设置文本内容,若通过NSString对象赋值,需要通过设置fontSize、foregroundColor等属性设置文本属性;也可以直接用NSAttributedString对象赋值。

3、缺点在于只能设置水平对齐方式,不能设置垂直对齐方式(默认垂直方向向上对齐,UILabel则是垂直方向默认居中对齐)。

    self.textLayer = [CATextLayer layer];
    self.textLayer.frame = CGRectMake(100, 100, 175, 100);
    self.textLayer.string = @"CATextLayer";
    self.textLayer.backgroundColor = [UIColor lightGrayColor].CGColor;
    self.textLayer.foregroundColor = [UIColor orangeColor].CGColor; //前景色(字体颜色)
    self.textLayer.fontSize = 20.0; //字体大小
    self.textLayer.wrapped = YES; //设置后会自动换行
    self.textLayer.alignmentMode = kCAAlignmentCenter;  //水平对齐方式
    self.textLayer.contentsScale = [UIScreen mainScreen].scale;  //使内容适配当前屏幕分辨率
    [self.view.layer addSublayer:self.textLayer];