3

使用下面的代码,我正在绘制一个圆角矩形。它绘制了一个漂亮的实心浅灰色填充圆角矩形(大小为“self”)。我其实是想画这个像素的倒数,也就是:不是实心圆角矩形,而是浅灰色实心矩形中这个圆角矩形形状的窗口或孔。

我需要使用反向剪辑方法吗?还是我需要使用贝塞尔路径?对不起,如果这是非常基本的,但找不到信息。

谢谢阅读!

- (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

将多个子路径添加到您的上下文中,并使用 mode 进行绘制kCGPathEOFillQuartz 2D Programming Guide 有更详细的解释。

// 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.swift到您的 Xcode 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. 在 Interface Builder 中绑定目标视图

在此处输入图像描述

  1. 在 IB 中调整插图、外部填充颜色、描边颜色和描边宽度!

在此处输入图像描述

  1. 设置您的约束和其他视图,请记住,如果您需要以特殊方式缩放矩形以进行旋转等,您可能必须修改 PortholeView。在这种情况下,我在 PortholeView 后面有一个 UIImage 来演示圆形矩形如何通过“奇偶规则”从周围路径中“切出”。

在此处输入图像描述

感谢 @matt 提供底层绘图代码,感谢 Apple 在 Interface Builder 中公开 IBInspectable/IBDesignable。

PS 这个古老的Cocoa with Love帖子将帮助您理解“偶数/奇数”规则及其兄弟“缠绕”规则,并提供一些用于绘制切口形状的额外策略。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

我一直在寻找做这个我正在做的项目。

我最终做了这样的事情。

在此处输入图像描述

我希望这可以帮助别人。

SWIFT代码:

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 回答