UIImageView class referenceによると、Apple は UIImageView をサブクラス化しないと言います。これを指摘してくれた @rob mayoff に感謝します。
ただし、独自の drawRect を実装する場合は、独自の UIView サブクラスから始めてください。そして、使用するのは drawRect 内ですaddClip
。CGPath に変換せずに UIBezierPath を使用してこれを行うことができます。
- (void)drawRect:(CGRect)rect
{
// This assumes the clippingPath and image may be drawn in the current coordinate space.
[[self clippingPath] addClip];
[[self image] drawAtPoint:CGPointZero];
}
境界を埋めるために拡大または縮小する場合は、グラフィックス コンテキストを拡大または縮小する必要があります。(clippingPath に a を適用することもできますがCGAffineTransform
、これは永続的であるため、最初に clippingPath をコピーする必要があります。)
- (void)drawRect:(CGRect)rect
{
// This assumes the clippingPath and image are in the same coordinate space, and scales both to fill the view bounds.
if ([self image])
{
CGSize imageSize = [[self image] size];
CGRect bounds = [self bounds];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextScaleCTM(context, bounds.size.width/imageSize.width, bounds.size.height/imageSize.height);
[[self clippingPath] addClip];
[[self image] drawAtPoint:CGPointZero];
}
}
これにより、各軸で画像が個別にスケーリングされます。縦横比を維持したい場合は、全体的なスケーリングを計算し、場合によってはそれを変換して、中央に配置するか、整列させる必要があります。
最後に、パスがたくさん描かれると、これらすべてが比較的遅くなります。おそらく、画像を CALayer に格納し、パスを含むCAShapeLayerでマスクする方が高速であることがわかるでしょう。 テスト以外では、次の方法を使用しないでください。画像レイヤーとマスクを別々にスケーリングして、それらを整列させる必要があります。利点は、下にあるイメージをレンダリングせずにマスクを変更できることです。
- (void) setImage:(UIImage *)image;
{
// This method should also store the image for later retrieval.
// Putting an image directly into a CALayer will stretch the image to fill the layer.
[[self layer] setContents:(id) [image CGImage]];
}
- (void) setClippingPath:(UIBezierPath *)clippingPath;
{
// This method should also store the clippingPath for later retrieval.
if (![[self layer] mask])
[[self layer] setMask:[CAShapeLayer layer]];
[(CAShapeLayer*) [[self layer] mask] setPath:[clippingPath CGPath]];
}
レイヤー マスクを使用した画像クリッピングを機能させる場合、 drawRect メソッドは不要になります。効率化のために削除します。