3

ユーザーが画像の一部を切り取ることができるアプリを作成しています。これを行うために、一連の UIBezierPath を作成してクリッピング パスを形成します。私の現在の設定は次のとおりです。

  • UIImageView は、カットしている画像を表示します。
  • その上にある UIImageView は、ユーザーが追加している UIBezierPaths を表示/更新するためのカスタム drawRect: メソッドを実行する UIImageView のカスタム サブクラスです。
  • ユーザーが「完了」ボタンをクリックすると、新しい UIBezierPath オブジェクトが作成されます。このオブジェクトには、ユーザーが作成した個々のパスが格納されている配列をループ処理し、それ自体で appendPath: を呼び出すことによって組み込まれています。この新しい UIBezierPath は、そのパスを閉じます。

それは私が得た限りです。UIBezierPath に addClip メソッドがあることは知っていますが、ドキュメントからその使用方法を理解できません。

一般に、私が見たクリッピングの例はすべて、UIBezierPath ラッパーではなく Core Graphics を直接使用しています。UIBezierPath には CGPath プロパティがあることに気付きました。では、完全な UIBezierPath オブジェクトではなく、クリッピング時にこれを使用する必要がありますか?

4

1 に答える 1

0

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 メソッドは不要になります。効率化のために削除します。

于 2012-04-09T00:07:17.983 に答える