基本属性
坐标属性
- frame:CGRect格式,定义其大小和在superView的坐标位置
- bounds:CGRect格式,定义其大小和在自己坐标系的位置
-
center:CGPoint格式,定义其在superView的中心点
demo
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 280, 250)];
[view1 setBounds:CGRectMake(-20, -20, 280, 250)];
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];//添加到self.view
NSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view2.backgroundColor = [UIColor yellowColor];
[view1 addSubview:view2];//添加到view1上,[此时view1坐标系左上角起点为(-20,-20)]
NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds));
透明度属性
-
hidden:BOOL,默认值是NO;为YES时
- 该view和其subViews都会从window中消失,不接收任何输入事件
- 该view会从响应链中移除,响应链中的第二个有效的view会成为第一响应者
-
opaque:BOOL,默认值是YES;但是当其设置为NO时,并没有消失,是因为
- GPU会对相重合的的部分进行重新计算,理想情况的公式R = S + D * ( 1 – Sa ),其中S表示源颜色[上层],D表示目标颜色[下层],Sa是S的opaque
- 如果opaque为YES,则公式变为R = S,不需要任何计算
- opaque其实是给绘图的性能优化开关
- 注意:这个是和alpha有关的,opaque为YES,alpha也必须为1.0
An opaque view is expected to fill its bounds with entirely opaque content—that is, the content should have an alpha value of 1.0. If the view is opaque and either does not fill its bounds or contains wholly or partially transparent content, the results are unpredictable. You should always set the value of this property to NO if the view is fully or partially transparent.
-
alpha:浮点值,取值范围0~1.0,表示从完全透明到完全不透明;默认值是1;当alpha设为0时
- 和hidden类似,view和subviews都会消失,该view会从响应链中被移除
- 会有动画效果,因为alpha是CALayer的隐式动画
内容属性
- contentMode:枚举类型,决定内容在view中如何展示的,比如图像是等比拉伸,还是填满view等等
transform
- transform在矩阵变换的层面上改变视图的显示效果,完成旋转、形变、平移等等操作。在它被修改的同时,视图的frame也会被真实改变。其是CGAffineTransform类型,2D层面的变化。还有个关于CALayer层面的3D操作:CATransform3D。
- 其原点是view.center或者layer.anchorPoint;默认值是CGAffineTransformIdentity矩阵。
- 常用的函数
// 用来连接两个变换效果并返回。返回的t = t1 * t2
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2)
// 矩阵初始值
CGAffineTransformIdentity
// 自定义矩阵变换
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)
// 旋转视图,传入参数为 角度 * (M_PI / 180);如:CGAffineTransformRotate(self.transform, angle)
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
// 缩放视图。如:CGAffineTransformScale(self.transform, sx, sy)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
// 平移视图。如:CGAffineTransformTranslate(self.transform, tx, ty)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
- (void)viewDidLoad {
[super viewDidLoad];
UIView *redView = [[UIView alloc]initWithFrame:CGRectMake((kScreenWidth - VIEW_WIDTH)/2, 60, VIEW_WIDTH, VIEW_HEIGHT)];
redView.backgroundColor = [UIColor redColor];
CGPoint anchorPoint = redView.layer.anchorPoint;
UIView *pointView = [[UIView alloc]initWithFrame:CGRectMake(anchorPoint.x*VIEW_WIDTH - POINT_W_H/2,anchorPoint.y*VIEW_HEIGHT -POINT_W_H/2 ,POINT_W_H ,POINT_W_H )];
pointView.layer.cornerRadius = POINT_W_H/2;
pointView.backgroundColor = [UIColor blackColor];
pointView.clipsToBounds = YES;
[redView addSubview:pointView];
[self.view addSubview:redView];
// [self performSelector:@selector(rotateView:) withObject:redView afterDelay:3];
// [self performSelector:@selector(translateView:) withObject:redView afterDelay:3];
[self performSelector:@selector(scaleView:) withObject:redView afterDelay:3];
}
- (void)rotateView:(UIView *)view
{
view.transform = CGAffineTransformRotate(view.transform, M_PI/6);
NSLog(@"view frame:%@========view bounds:%@",NSStringFromCGRect(view.frame),NSStringFromCGRect(view.bounds));
NSLog(@"view layer posistion:%@========view layer anchorPoint:%@",NSStringFromCGPoint(view.layer.position),NSStringFromCGPoint(view.layer.anchorPoint));
[self performSelector:@selector(rotateView:) withObject:view afterDelay:1];
}
- (void)translateView:(UIView *)view
{
view.transform = CGAffineTransformTranslate(view.transform, VIEW_WIDTH/10, VIEW_HEIGHT/10);
[self performSelector:@selector(translateView:) withObject:view afterDelay:1];
}
- (void)scaleView:(UIView *)view
{
//缩小
view.transform = CGAffineTransformScale(view.transform , 0.8, 0.8 );
//放大
// view.transform = CGAffineTransformScale(view.transform , 1.25, 1.25 );
[self performSelector:@selector(scaleView:) withObject:view afterDelay:1];
}
//增加动画过程展示,以rotate为例
- (void)rotateViewWithAnimation:(UIView *)view
{
[UIView animateWithDuration: 3. animations: ^ {
view.transform = CGAffineTransformRotate(view.transform, M_PI/6);
}];
}
setNeedsDisplay、setNeedsLayout、layoutIfNeeded、layoutSubviews
- 布局/定位相关
- setNeedsLayout:在receiver标上一个需要被重新布局的标记,在系统runloop的下一个周期自动调用layoutSubviews
- layoutIfNeeded:会遍历subviews链,如果需要layout,立即调用layoutSubviews
- layoutSubviews:核心函数,最终的目的就是调用该函数,开发者不要直接调用该函数,但可以重写该函数,来加入些自己的代码。该函数只会进行位置,视图大小的数字计算,并不会引起屏幕的绘制。
在苹果的官方文档中强调: You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.自动布局达不到想要效果时你才有必要重写这个方法.可以直接设置subviews的尺寸;不要直接调用这个方法,因为不会有任何的作用.如果你需要强制layout刷新,调用setNeedsLayout来代替; 如果你想要立即刷新你的view,调用layoutIfNeeded.
- 显示相关
- setNeedsDisplay:在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘
- setNeedsDisplayInRect:不但设置了标记,而且详细规定了需要刷新的区域。
- drawRect:核心函数,将重绘的结果显示到屏幕上。开发人员不可以直接调用该函数,只能重写该函数,额外做一些事。
- 约束相关(Auto layout)
- setNeedsUpdateCOnstraints:当一个自定义view的某个属性发生改变,并且可能影响到constraint时,需要调用此方法去标记constraints需要在未来的某个点更新,系统然后调用updateConstraints。
- updateConstraintsIfNeeded:如果需要更新约束,立即执行
- updateConstraints:自定义view应该重写此方法在其中建立constraints
layoutSubviews在以下情况下会被调用:
- init初始化不会触发layoutSubviews
- addSubview会触发layoutSubviews
- 设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
- 滚动一个UIScrollView会触发layoutSubviews
- 旋转Screen会触发父UIView上的layoutSubviews事件
- 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
drawRect在以下情况下会被调用:
- 如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect调用是在Controller->loadView, Controller->viewDidLoad两个方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了。这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值)。
- 该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
- 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
- 直接调用setNeedsDisplay或者setNeedsDisplayInRect: 触发drawRect:,但是有个前提条件是rect不能为0。
参考
UIView 文档
理解position和anchorPoint
iOS动画-Transform和KeyFrame动画
CGAffineTransform放射变换
内存恶鬼drawRect - 谈画图功能的内存优化