菜鸟教程小白 发表于 2022-12-13 11:55:54

ios - 如何实现执行 contentStretch 反转的 UIView?


                                            <p><p>UIView <a href="https://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIView_Class/UIView/UIView.html" rel="noreferrer noopener nofollow">contentStretch</a>属性定义了一个区域,在该区域内内容被拉伸(stretch)以填充 View 。这很好,但我发现自己需要完全相反的东西:我想要一个 View ,我可以定义一个不拉伸(stretch)但外边缘拉伸(stretch)直到填满 View 的矩形。 </p>

<pre><code>+-------------------------------------------+
|                                           |
|         +----------+                      |
|         |          |                      |
|         |          |                      |
|         |Content |      Stretch to fill |
|         |          |                      |
|         |          |                      |
|         +----------+                      |
|                                           |
+-------------------------------------------+
</code></pre>

<p>所以在上面的 View 中,外部矩形是我提出的 View 。内部矩形是不可拉伸(stretch)的内容。理想情况下,我希望能够将不可拉伸(stretch)内容的中心点定位在外部矩形内的任何位置,并且仍然让外部位填充到边缘。</p>

<p>示例使用场景:带有透明中心“孔”的黑色覆盖层,跟随鼠标/触摸,用于使用手电筒等探索场景。</p>

<p>我想这样做的一种方法是绘制内容 UIView,然后绘制其他四个 View ,大小适当,以覆盖外部区域,但我希望有一个单 View 解决方案来实现更流畅的动画效果。我猜我需要一个 UIView 并使用 Core Animation 来弄乱它的图层? </p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>所以我的第一次尝试(在我对这个问题的另一个回答中),在 <code>drawRect:</code> 中做所有事情,在我的 iPad 2 上有点滞后。我决定通过创建一个单独的 <code>CALayer</code> 每个切片,让 Core Animation 担心缩放切片。</p>

<p>在这个版本中,工作是在我的自定义 <code>UIView</code> 子类的 <code>layoutSubviews</code> 方法中完成的。只要 View 的大小发生变化(包括 View 首次出现时),系统就会调用 <code>layoutSubviews</code>。我们还可以使用 <code>setNeedsLayout</code> 消息要求系统调用 <code>layoutSubviews</code>。系统会自动合并布局请求,就像合并绘图请求一样。</p>

<p>我需要三个私有(private)实例变量:</p>

<pre><code>@implementation OutstretchView {
    CALayer *_slices;
    BOOL _imageDidChange : 1;
    BOOL _hasSlices : 1;
}
</code></pre>

<p>我的 <code>layoutSubviews</code> 方法从处理没有图像或没有 <code>fixedRect</code> 的简单情况开始:</p>

<pre><code>- (void)layoutSubviews {
    ;

    if (!self.image) {
      ;
      self.layer.contents = nil;
      return;
    }

    if (CGRectIsNull(self.fixedRect)) {
      ;
      self.layer.contents = (__bridge id)self.image.CGImage;
      return;
    }
</code></pre>

<p>如果我还没有创建九个切片层,它会懒惰地创建它们:</p>

<pre><code>    if (!_hasSlices)
      ;
</code></pre>

<p>如果图像发生变化,它会重新计算切片层的图像。 <code>_imageDidChange</code> 标志在 <code>setImage:</code> 中设置。</p>

<pre><code>    if (_imageDidChange) {
      ;
      _imageDidChange = NO;
    }
</code></pre>

<p>最后,它设置九个切片层中每一层的框架。</p>

<pre><code>    ;
}
</code></pre>

<p>当然,所有实际工作都发生在辅助方法中,但它们非常简单。隐藏切片(当没有图像或没有 <code>fixedRect</code> 时)很简单:</p>

<pre><code>- (void)hideSlices {
    if (!_hasSlices)
      return;
    for (int y = 0; y &lt; 3; ++y) {
      for (int x = 0; x &lt; 3; ++x) {
            _slices.hidden = YES;
      }
    }
}
</code></pre>

<p>创建切片层也很简单:</p>

<pre><code>- (void)makeSlices {
    if (_hasSlices)
      return;
    CALayer *myLayer = self.layer;
    for (int y = 0; y &lt; 3; ++y) {
      for (int x = 0; x &lt; 3; ++x) {
            _slices = ;
            ];
      }
    }
    _hasSlices = YES;
}
</code></pre>

<p>要制作切片图像并设置切片图层帧,我需要其他答案中的 <code>rect</code> 辅助函数:</p>

<pre><code>static CGRect rect(CGFloat *xs, CGFloat *ys) {
    return CGRectMake(xs, ys, xs - xs, ys - ys);
}
</code></pre>

<p>创建切片图像需要一些工作,因为我必须计算切片之间边界的坐标。我使用 <code>CGImageCreateWithImageInRect</code> 从用户提供的图像创建切片图像。</p>

<pre><code>- (void)setSliceImages {
    UIImage *image = self.image;
    CGImageRef cgImage = image.CGImage;
    CGFloat scale = image.scale;
    CGRect fixedRect = self.fixedRect;
    fixedRect.origin.x *= scale;
    fixedRect.origin.y *= scale;
    fixedRect.size.width *= scale;
    fixedRect.size.height *= scale;
    CGFloat xs = { 0, fixedRect.origin.x, CGRectGetMaxX(fixedRect), CGImageGetWidth(cgImage) };
    CGFloat ys = { 0, fixedRect.origin.y, CGRectGetMaxY(fixedRect), CGImageGetHeight(cgImage) };

    for (int y = 0; y &lt; 3; ++y) {
      for (int x = 0; x &lt; 3; ++x) {
            CGImageRef imageSlice = CGImageCreateWithImageInRect(cgImage, rect(xs + x, ys + y));
            _slices.contents = (__bridge id)imageSlice;
            CGImageRelease(imageSlice);
      }
    }
}
</code></pre>

<p>设置切片层帧是类似的,虽然我不必在这里处理图像比例。 (也许我应该使用 <code>UIScreen</code> 比例尺?嗯。这令人困惑。我没有在 Retina 设备上尝试过。)</p>

<pre><code>- (void)setSliceFrames {
    CGRect bounds = self.bounds;
    CGRect fixedRect = self.fixedRect;
    CGPoint fixedCenter = self.fixedCenter;
    fixedRect = CGRectOffset(fixedRect, fixedCenter.x - fixedRect.size.width / 2, fixedCenter.y - fixedRect.size.height / 2);
    CGFloat xs = { bounds.origin.x, fixedRect.origin.x, CGRectGetMaxX(fixedRect), CGRectGetMaxX(bounds) };
    CGFloat ys = { bounds.origin.y, fixedRect.origin.y, CGRectGetMaxY(fixedRect), CGRectGetMaxY(bounds) };

    for (int y = 0; y &lt; 3; ++y) {
      for (int x = 0; x &lt; 3; ++x) {
            _slices.frame = rect(xs + x, ys + y);
      }
    }
}
</code></pre>

<p>这个版本在我的 iPad 2 上似乎更流畅。它可能在旧设备上也能很好地工作。</p>

<p>我的测试项目的这个版本是<a href="https://github.com/mayoff/stackoverflow-OutstretchView" rel="noreferrer noopener nofollow">on github too</a> .</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 如何实现执行 contentStretch 反转的 UIView?,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/9493337/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/9493337/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 如何实现执行 contentStretch 反转的 UIView?