3

以下のコードを使用して、角の丸い長方形を描画しています。明るい灰色で塗りつぶされた丸みを帯びた長方形(「自己」のサイズ)を描画します。私は実際にこれの逆のピクセルを描きたいと思っています。つまり、丸い長方形ではなく、明るい灰色の長方形のこの丸い長方形の形をした窓または穴です。

使用する必要のあるリバースクリップ方式はありますか?または、ベジェパスを使用する必要がありますか?これが非常に基本的なものである場合は申し訳ありませんが、情報が見つかりません。

読んでくれてありがとう!

- (void)drawRect:(CGRect)rect
{

    // get the context
    CGContextRef context = UIGraphicsGetCurrentContext

    CGContextSaveGState(context);    

    //draw the rounded rectangle
    CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
    CGContextSetRGBFillColor(context, 0.8, 0.8, 0.8, 1.0);
    CGContextSetLineWidth(context, _lineWidth);

    CGRect rrect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect), CGRectGetHeight(rect));
    CGFloat radius = _cornerRadius;

    CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
    CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);

    CGContextMoveToPoint(context, minx, midy);
    // Add an arc through 2 to 3
    CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
    // Add an arc through 4 to 5
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
    // Add an arc through 6 to 7
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
    // Add an arc through 8 to 9
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
    // Close the path
    CGContextClosePath(context);

    // Fill the path
    CGContextDrawPath(context, kCGPathFill);

    CGContextRestoreGState(context);

}
4

5 に答える 5

12

UIオブジェクト呼び出しだけを使用するさらに別のアプローチは次のとおりです。

- (void)drawRect:(CGRect)rect
{
    [[UIColor lightGrayColor] setFill];
    CGRect r2 = CGRectInset(rect, 10, 10);
    UIBezierPath* p = [UIBezierPath bezierPathWithRoundedRect:r2 cornerRadius:15];
    [p appendPath: [UIBezierPath bezierPathWithRect:rect]];
    p.usesEvenOddFillRule = YES;
    [p fill];
}

これを生成します:

ここに画像の説明を入力してください

白はウィンドウの背景です。灰色はUIViewです。ご覧のとおり、背後にあるものすべてを眺めることができます。これは、あなたが説明していることのように聞こえます。

于 2013-01-04T05:09:44.037 に答える
4

コンテキストに複数のサブパスを追加し、モードで描画しますkCGPathEOFillQuartz2Dプログラミングガイドで詳しく説明されています。

// Outer subpath: the whole rect
CGContextAddRect(context, rrect);

// Inner subpath: the area inside the whole rect    
CGContextMoveToPoint(context, minx, midy);
...
// Close the inner subpath
CGContextClosePath(context);

// Fill the path
CGContextDrawPath(context, kCGPathEOFill);
于 2013-01-03T18:22:37.493 に答える
4

ドロップインソリューションの場合:

  1. PortholeView.swiftXcode 6(またはそれ以降)プロジェクトに追加する

    import UIKit
    
    @IBDesignable class PortholeView: UIView {
      @IBInspectable var innerCornerRadius: CGFloat = 10.0
      @IBInspectable var inset: CGFloat = 20.0
      @IBInspectable var fillColor: UIColor = UIColor.grayColor()
      @IBInspectable var strokeWidth: CGFloat = 5.0
      @IBInspectable var strokeColor: UIColor = UIColor.blackColor()
    
      override func drawRect(rect: CGRect) {
        // Prep constants
        let roundRectWidth = rect.width - (2 * inset)
        let roundRectHeight = rect.height - (2 * inset)
    
        // Use EvenOdd rule to subtract portalRect from outerFill
        // (See http://stackoverflow.com/questions/14141081/uiview-drawrect-draw-the-inverted-pixels-make-a-hole-a-window-negative-space)
        let outterFill = UIBezierPath(rect: rect)
        let portalRect = CGRectMake(
          rect.origin.x + inset,
          rect.origin.y + inset,
          roundRectWidth,
          roundRectHeight)
        fillColor.setFill()
        let portal = UIBezierPath(roundedRect: portalRect, cornerRadius: innerCornerRadius)
        outterFill.appendPath(portal)
        outterFill.usesEvenOddFillRule = true
        outterFill.fill()
        strokeColor.setStroke()
        portal.lineWidth = strokeWidth
        portal.stroke()
      }
    }
    
  2. InterfaceBuilderでターゲットビューをバインドします

ここに画像の説明を入力してください

  1. インセット、アウターフィルの色、ストロークの色、ストロークの幅をIBで正しく調整してください。

ここに画像の説明を入力してください

  1. 回転などの特別な方法でrectをスケーリングする必要がある場合は、PortholeViewを変更する必要がある可能性があることに注意して、制約やその他のビューを設定します。この場合、PortholeViewの背後にUIImageがあり、「偶数の奇妙なルール」のおかげで、丸い長方形が周囲のパスからどのように「切り取られる」かを示しています。

ここに画像の説明を入力してください

基礎となる描画コードを提供してくれた@mattと、InterfaceBuilderでIBInspectable/IBDesignableを公開してくれたAppleに感謝します。

PSこの由緒あるCocoawithLoveの投稿は、「偶数/奇数」ルールとその兄弟である「ワインディング」ルールを理解するのに役立つだけでなく、カットアウト形状を描画するためのいくつかの追加戦略を提供します。http://www.cocoawithlove.com/2010/05/5-ways-to-draw-2d-shape-with-hole-in.html

于 2015-07-06T20:33:34.510 に答える
1

別のアプローチ:UICreateGraphicsContextWithOptions(size, NO, 0)ビットマップを作成するために使用します。長方形をビットマップに描画します。消去ブレンドモードに切り替えます。

CGContextSetBlendMode(con, kCGBlendModeClear);

次に、楕円形のパスを描画して塗りつぶします。結果は、透明な楕円形の穴のある長方形になります。次に、画像グラフィックスコンテキストを閉じて、画像を元のコンテキストに描画します。

于 2013-01-03T19:28:56.200 に答える
1

私は自分が取り組んでいるプロジェクトでこれを行うために周りを探していました。

私はこのようなことをすることになった。

ここに画像の説明を入力してください

これが誰かに役立つことを願っています。

スウィフトコード:

import UIKit

class BarCodeReaderOverlayView: UIView {

    @IBOutlet weak var viewFinderView: UIView!

    // MARK: - Drawing

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)

        if self.viewFinderView != nil {
            // Ensures to use the current background color to set the filling color
            self.backgroundColor?.setFill()
            UIRectFill(rect)

            let layer = CAShapeLayer()
            let path = CGPathCreateMutable()

            // Make hole in view's overlay
            CGPathAddRect(path, nil, self.viewFinderView.frame)
            CGPathAddRect(path, nil, bounds)

            layer.path = path
            layer.fillRule = kCAFillRuleEvenOdd
            self.layer.mask = layer
        }
    }

    override func layoutSubviews () {
        super.layoutSubviews()
    }

    // MARK: - Initialization

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
}
于 2015-10-05T05:08:46.813 に答える