来自 电脑系统 2019-09-14 02:58 的文章
当前位置: 金沙澳门官网网址 > 电脑系统 > 正文

Techniques图层几何学

但是: 如果是有导航条,且默认的控制器的<code> UIView</code>有子控件是继承<code> UIScrollView</code>的会在调用了<code> viewDidLayoutSubviews</code>这个方法中默认给这些子控件的内边距的顶部top增加导航条的高度也就是<code> 64 </code>

图片 1boyXiong

结果表明:很明显的<code> Bounds</code>的<code> y </code> 值和内边距的<code> top </code>值发生了改变</br> 如何去掉这个功能,如果是代码创建的设置这个属性为<code> false</code>就可以了

//Swift 写法self.navigationController?.automaticallyAdjustsScrollViewInsets = false

如果是<code> User Interface </code> 那么就去掉勾选 图片 2boyXiong

</a></p>

简单的说</br>

<code>frame</code> 指的是这个<code>view</code>在它<code>superview</code>的坐标系的坐标和大小.

<code>bounds</code>指这个<code>view</code>在它自己坐标系的坐标和大小</div></br>

通俗的说整个APP相当于一栋房子,而<code>frame</code>相当于窗户,窗户的位置是相对于墙壁来说的,但是<code> Bounds</code> 相当于窗户里面要显示什么内容的位置</br>

<p>记住当对图层做变换的时候,比如旋转或者缩放,<code>frame</code>实际上代表了覆盖在图层旋转之后的整个轴对齐的矩形区域,也就是说<code>frame</code>的宽高可能和<code>bounds</code>的宽高不再一致了</p>

注意: 每个新建的<code> View</code>的<code> bounds</code>默认的 <code> </code> 都是 <code> </code>

图片 3图3.6

图片 4图3.3

<p><code>CALayer</code>并不关心任何响应链事件,所以不能直接处理触摸事件或者手势。但是它有一系列的方法帮你处理事件:<code>-containsPoint:</code>和<code>-hitTest:</code>。</p>

<p>清单3.1 <strong>Clock</strong></p>

<p>这意味着如果改变了图层的z轴顺序,你会发现将不能够检测到最前方的视图点击事件,这是因为被另一个图层遮盖住了,虽然它的<code>zPosition</code>值较小,但是在图层树中的顺序靠前。我们将在第五章详细讨论这个问题。</p>

<p>图3.1 <code>UIView</code>和<code>CALayer</code>的坐标系</p>

<p>图3.5 在Interface Builder中布局闹钟视图</p>

<p><code>zPosition</code>属性在大多数情况下其实并不常用。在第五章,我们将会涉及<code>CATransform3D</code>,你会知道如何在三维空间移动和旋转图层,除了做变换之外,<code>zPosition</code>最实用的功能就是改变图层的<em>显示顺序</em>了。</p>

<h2> 锚点</h2>

<p>视图的<code>frame</code>,<code>bounds</code>和<code>center</code>属性仅仅是<em>存取方法</em>,当操纵视图的<code>frame</code>,实际上是在改变位于视图下方<code>CALayer</code>的<code>frame</code>,不能够独立于图层之外改变视图的<code>frame</code>。</p>

<p>清单3.2</p>

<p><code>CALayer</code>给不同坐标系之间的图层转换提供了一些工具类方法:</p>

<p>图3.3 改变<code>anchorPoint</code>的效果</p>

<p>这些方法可以把定义在一个图层坐标系下的点或者矩形转换成另一个图层坐标系下的点或者矩形</p>

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIImageView *hourHand;@property (nonatomic, weak) IBOutlet UIImageView *minuteHand;@property (nonatomic, weak) IBOutlet UIImageView *secondHand;@property (nonatomic, weak) NSTimer *timer;@end@implementation ViewController- viewDidLoad{ [super viewDidLoad]; //start timer self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector userInfo:nil repeats:YES]; //set initial hand positions [self tick];}- tick{ //convert time to hours, minutes and seconds NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; NSDateComponents *components = [calendar components:units fromDate:[NSDate date]]; CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0; //calculate hour hand angle //calculate minute hand angle CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0; //calculate second hand angle CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0; //rotate hands self.hourHand.transform = CGAffineTransformMakeRotation(hoursAngle); self.minuteHand.transform = CGAffineTransformMakeRotation(minsAngle); self.secondHand.transform = CGAffineTransformMakeRotation(secsAngle);}@end

<p>本章涉及了<code>CALayer</code>的集合结构,包括它的<code>frame</code>,<code>position</code>和<code>bounds</code>,介绍了三维空间内图层的概念,以及如何在独立的图层内响应事件,最后简单说明了在iOS平台,Core Animation对自动调整和自动布局支持的缺乏。</p>

<h2> Hit Testing</h2>

<p>那在什么场合需要改变<code>anchorPoint</code>呢?既然我们可以随意改变图层位置,那改变<code>anchorPoint</code>不会造成困惑么?为了举例说明,我们来举一个实用的例子,创建一个模拟闹钟的项目。</p>

<p><code>frame</code>代表了图层的外部坐标(也就是在父图层上占据的空间),<code>bounds</code>是内部坐标({0, 0}通常是图层的左上角),<code>center</code>和<code>position</code>都代表了相对于父图层<code>anchorPoint</code>所在的位置。<code>anchorPoint</code>的属性将会在后续介绍到,现在把它想成图层的中心点就好了。图3.1显示了这些属性是如何相互依赖的。</p>

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@property (nonatomic, weak) CALayer *blueLayer;@end@implementation ViewController- viewDidLoad{ [super viewDidLoad]; //create sublayer self.blueLayer = [CALayer layer]; self.blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f); self.blueLayer.backgroundColor = [UIColor blueColor].CGColor; //add it to our view [self.layerView.layer addSublayer:self.blueLayer];}- touchesBegan:touches withEvent:(UIEvent *)event{ //get touch position relative to main view CGPoint point = [[touches anyObject] locationInView:self.view]; //convert point to the white layer's coordinates point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer]; //get layer using containsPoint: if ([self.layerView.layer containsPoint:point]) { //convert point to blueLayer’s coordinates point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer]; if ([self.blueLayer containsPoint:point]) { [[[UIAlertView alloc] initWithTitle:@"Inside Blue Layer" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } else { [[[UIAlertView alloc] initWithTitle:@"Inside White Layer" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; } }}@end

<p>之前提到过,视图的<code>center</code>属性和图层的<code>position</code>属性都指定了<code>anchorPoint</code>相对于父图层的位置。图层的<code>anchorPoint</code>通过<code>position</code>来控制它的<code>frame</code>的位置,你可以认为<code>anchorPoint</code>是用来移动图层的<em>把柄</em>。</p>

图片 5图3.8

图片 6图3.5

<h3> Z坐标轴</h3>

<p>图3.10 点击图层被正确标识</p>

图片 7图3.10

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *greenView;@property (nonatomic, weak) IBOutlet UIView *redView;@end@implementation ViewController- viewDidLoad{ [super viewDidLoad]; //move the green view zPosition nearer to the camera self.greenView.layer.zPosition = 1.0f;}@end

<p>图3.8 在视图层级中绿色视图被绘制在红色视图的后面</p>

<pre><code>- convertPoint:point fromLayer:(CALayer *)layer;

<p>我们用<code>NSTimer</code>来更新闹钟,使用视图的<code>transform</code>属性来旋转钟表(如果你对这个属性不太熟悉,不要着急,我们将会在第5章“变换”当中详细说明),具体代码见清单3.1</p>

图片 8图3.2

<p><code>-hitTest:</code>方法同样接受一个<code>CGPoint</code>类型参数,而不是<code>BOOL</code>类型,它返回图层本身,或者包含这个坐标点的叶子节点图层。这意味着不再需要像使用<code>-containsPoint:</code>那样,人工地在每个子图层变换或者测试点击的坐标。如果这个点在最外面图层的范围之外,则返回nil。具体使用<code>-hitTest:</code>方法被点击图层的代码如清单3.5所示。</p>

<p>当使用视图的时候,可以充分利用<code>UIView</code>类接口暴露出来的<code>UIViewAutoresizingMask</code>和<code>NSLayoutConstraint</code>API,但如果想随意控制<code>CALayer</code>的布局,就需要手工操作。最简单的方法就是使用<code>CALayerDelegate</code>如下函数:</p>

  • convertPoint:point toLayer:(CALayer *)layer;
  • convertRect:rect fromLayer:(CALayer *)layer;
  • convertRect:rect toLayer:(CALayer *)layer;</code></pre>

<p>清单3.4 使用containsPoint判断被点击的图层</p>

<p>在iOS6中,苹果介绍了<em>自动排版</em>机制,它和自动调整不同,并且更加复杂。</p>

<p>我们希望在真实的应用中也能显示出绘图的顺序,同样地,如果我们提高绿色视图的<code>zPosition</code>,我们会发现顺序就反了。其实并不需要增加太多,视图都非常地薄,所以给<code>zPosition</code>提高一个像素就可以让绿色视图前置,当然0.1或者0.0001也能够做到,但是最好不要这样,因为浮点类型四舍五入的计算可能会造成一些不便的麻烦。</p>

<p>常规说来,在iOS上,一个图层的<code>position</code>位于父图层的左上角,但是在Mac OS上,通常是位于左下角。Core Animation可以通过<code>geometryFlipped</code>属性来适配这两种情况,它决定了一个图层的坐标是否相对于父图层垂直翻转,是一个<code>BOOL</code>类型。在iOS上通过设置它为<code>YES</code>意味着它的子图层将会被垂直翻转,也就是将会沿着底部排版而不是通常的顶部(它的所有子图层也同理,除非把它们的<code>geometryFlipped</code>属性也设为<code>YES</code>)。</p>

<h2> 自动布局</h2>

<p><code>UIView</code>有三个比较重要的布局属性:<code>frame</code>,<code>bounds</code>和<code>center</code>,<code>CALayer</code>对应地叫做<code>frame</code>,<code>bounds</code>和<code>position</code>。为了能清楚区分,图层用了“position”,视图用了“center”,但是他们都代表同样的值。</p>

<p>图3.2 旋转一个视图或者图层之后的<code>frame</code>属性</p>

<p>图3.9 绿色视图被绘制在红色视图的前面</p>

本文由金沙澳门官网网址发布于电脑系统,转载请注明出处:Techniques图层几何学

关键词: