大概你不需要四个其他视图,你需要八个。内部“固定”矩形将视图分为九个切片:
+----+-----+---------+
| | | |
+----+-----+---------|
| |fixed| |
| | | |
+----+-----+---------+
| | | |
| | | |
| | | |
+----+-----+---------+
请注意,九个切片中的每一个都可能需要不同的水平和垂直缩放组合。它最终看起来像这样:
无论如何,我认为通过创建一个覆盖drawRect: 的UIView 子类来做到这一点并不难。
我将我的子类命名为 OutstretchView 并赋予它三个属性:
@interface OutstretchView : UIView
@property (nonatomic) UIImage *image;
@property (nonatomic) CGRect fixedRect; // in image coordinates
@property (nonatomic) CGPoint fixedCenter; // in view coordinates
@end
fixedRect 属性定义了图像中不应该被拉伸的部分。 fixedCenter 属性定义了应该在视图中的哪个位置绘制图像的一部分。
要实际绘制图像的九个切片,定义一个方法是有帮助的的看法。我使用 Quartz 2D 的剪辑和 CTM 功能来完成“繁重的工作”:
- (void)drawRect:(CGRect)imageRect ofImage:(UIImage *)image inRect:(CGRect)viewRect {
CGContextRef gc = UIGraphicsGetCurrentContext();
CGContextSaveGState(gc); {
CGContextClipToRect(gc, viewRect);
CGContextTranslateCTM(gc, viewRect.origin.x, viewRect.origin.y);
CGContextScaleCTM(gc, viewRect.size.width / imageRect.size.width, viewRect.size.height / imageRect.size.height);
CGContextTranslateCTM(gc, -imageRect.origin.x, -imageRect.origin.y);
[image drawAtPoint:CGPointZero];
} CGContextRestoreGState(gc);
}
我还将使用一个小助手方法,从两个 X 坐标的数组和一个两个 Y 坐标的数组创建一个 CGRect:
static CGRect rect(CGFloat *xs, CGFloat *ys) {
return CGRectMake(xs[0], ys[0], xs[1] - xs[0], ys[1] - ys[0]);
}
有了这些助手,我可以实现drawRect:。首先,我处理没有要绘制的图像或没有定义fixedRect 的简单情况:
- (void)drawRect:(CGRect)dirtyRect {
UIImage *image = self.image;
if (!image)
return;
CGRect imageBounds = (CGRect){ CGPointZero, image.size };
CGRect viewBounds = self.bounds;
CGRect imageFixedRect = self.fixedRect;
if (CGRectIsNull(imageFixedRect)) {
[image drawInRect:viewBounds];
return;
}
然后我计算将绘制图像固定部分的视图坐标中的矩形:
CGPoint imageFixedCenter = self.fixedCenter;
CGRect viewFixedRect = CGRectOffset(imageFixedRect, imageFixedCenter.x - imageFixedRect.size.width / 2, imageFixedCenter.y - imageFixedRect.size.height / 2);
接下来,我创建了一个包含四个(是的,四个)X 坐标的数组,用于定义视图坐标空间中切片的边缘,以及一个类似的 Y 坐标数组,以及另外两个数组用于图像坐标空间中的坐标:
CGFloat viewSlicesX[4] = { viewBounds.origin.x, viewFixedRect.origin.x, CGRectGetMaxX(viewFixedRect), CGRectGetMaxX(viewBounds) };
CGFloat viewSlicesY[4] = { viewBounds.origin.y, viewFixedRect.origin.y, CGRectGetMaxY(viewFixedRect), CGRectGetMaxY(viewBounds) };
CGFloat imageSlicesX[4] = { imageBounds.origin.x, imageFixedRect.origin.x, CGRectGetMaxX(imageFixedRect), CGRectGetMaxX(imageBounds) };
CGFloat imageSlicesY[4] = { imageBounds.origin.y, imageFixedRect.origin.y, CGRectGetMaxY(imageFixedRect), CGRectGetMaxY(imageBounds) };
最后是最简单的部分,绘制切片:
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
[self drawRect:rect(imageSlicesX + x, imageSlicesY + y) ofImage:image inRect:rect(viewSlicesX + x, viewSlicesY + y)];
}
}
}
在我的 iPad 2 上有点滞后。
我的测试项目的这个版本是on github。