contentMode属性
每个UIView都有一个contentMode属性控制视图如何回收利用其内容以响应视图几何体都改变以及是否回收其内容。
// UIView类中都contentMode属性
@property(nonatomic) UIViewContentMode contentMode; // default is UIViewContentModeScaleToFill
// UIViewContentMode的定义:用于指定视图在其大小更改时如何调整其内容的选项
typedef NS_ENUM(NSInteger, UIViewContentMode) {
UIViewContentModeScaleToFill, //根据需要通过更改内容的高宽比来缩放内容以适应其自身大小, 会使内容充满容器,该选项会导致变形
UIViewContentModeScaleAspectFit, // contents scaled to fit with fixed aspect. remainder is transparent 通过保持高宽比来缩放内容以适应视图大小。视图边界的任何剩余区域都是透明的。会保证内容比例不变,而且全部显示在View中,这意味着View会有部分空白,不会填充整个区域。
UIViewContentModeScaleAspectFill, // contents scaled to fill with fixed aspect. some portion of content may be clipped. 缩放内容以填充视图大小。内容的某些部分可能会被裁剪以填充视图的边界。会证图片比例不变,但是是填充整个View的,可能只有部分图片显示出来。
UIViewContentModeRedraw, // redraw on bounds change (calls -setNeedsDisplay) 当bounds更改的时候重绘调用drawRect:
UIViewContentModeCenter, // contents remain same size. positioned adjusted. 内容大小不变,位置调整
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,
};
关于UIViewContentModeRedraw:当bounds更改当时候系统会根据是UIViewContentModeRedraw值调用setNeedDisplay方法, 该方法告诉系统调用drawRect:重绘内容
首次显示视图时,它会像往常一样渲染其内容,并将结果捕获到底层的位图中。 之后,对视图几何体的更改并不总是会导致重新创建位图。 相反,contentMode属性中的值决定是否缩放位图以适应新的边界,或者只是固定位图到视图的一个角或边缘。
每当您执行以下操作时,都会应用视图的contentMode:
- 改变视图frame或bounds的高和宽
- 将包含比例因子的仿射变换(transform)分配给视图的transform属性
默认情况下,大多数视图的contentMode属性设置为UIViewContentModeScaleToFill,这会导致视图的内容被缩放以适应新的frame大小。
上面图显示了可用的某些内容模式(contentMode)的结果。 从图中可以看出,并非所有的内容模式(contentMode)都会导致视图的边界被完全填满,而那些内容模式(contentMode)可能会扭曲视图的内容。
UIViewContentModeLeft UIViewContentModeScaleAspectFill UIViewContentModeScaleAspectFit UIViewContentModeScaleToFill如果您希望自定义视图在缩放和调整大小操作期间重新绘制内容,则还可以将内容模式设置为UIViewContentModeRedraw值。 将视图的内容模式设置为这个值会迫使系统调用视图的drawRect:方法来响应几何变化。 一般而言,您应尽可能避免使用此值,并且您绝对不应将其用于标准系统视图。
关于UIViewConentMode的使用在UIImageView中比较常见
Demo演示
新建一个Application:建立一个UIView的子类, 使用交互方式(点击按钮)动态更改UIView的位置和大小观察其drawRect调用情况
#import "ViewController.h"
@interface SubView : UIView
@end
@implementation SubView
- (void)drawRect:(CGRect)rect {
static int i = 0;
NSLog(@"draw Rect in Subview %@", @(i));
++i;
}
@end
@interface ViewController ()
{
SubView *_subView;
UIButton *_button;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_subView = [[SubView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[_subView setBackgroundColor:[UIColor purpleColor]];
[self.view addSubview:_subView];
_button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
[_button setBackgroundColor:[UIColor redColor]];
[_button addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_button];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)tapButton:(UIButton *)button {
CGRect subViewFrame = _subView.frame;
static int b = 0;
if (b % 2) {
subViewFrame.origin.x += 5;
if (subViewFrame.origin.x >= 350) {
subViewFrame.origin.x = 5;
}
} else {
subViewFrame.size.height += 5;
if (subViewFrame.size.height >= 400) {
subViewFrame.size.height = 5;
}
}
b++;
[_subView setFrame:subViewFrame];
}
@end
结果:_subView位置和大小在每次点击下更改,_subView的drawRect:只调用了一次。原位图填充整个视图
原因分析:_subView的contentMode默认为UIViewContentModeScaleToFill, 在每次bounds或frames大大小更改的时候,会复用第一次展示生成的位图,。
对Demo进行更改1:将_subView的contentMode更改为UIViewContentModeRedraw, 则_subView大小更改时,_subView的drawRect:都会调用,在位置更改的时候不会调用。
对Demo进行更改2:将_subView的contentMode更改为UIViewContentModeLeft,_subView位置和大小在每次点击下更改,_subView的drawRect:只调用了一次。原位图大小不变的置于视图的左边。
如图(截图自Debug View Hierarchy)紫色矩形框为原位图大小,紫色矩形框外的选中状态的白色矩形框为改变后的视图大小。
UIViewContentModeLeft样式.png
网友评论