Swift iOS从视图中切出圆角矩形,允许更改颜色

时间:2019-07-02 16:28:31

标签: ios swift animation uikit

我正在使用这种方法从背景视图中切出一个圆形的矩形“窗口”:

override func draw(_ rect: CGRect) {
        guard let rectsArray = rectsArray else {
            return
        }

        for holeRect in rectsArray {
            let holeRectIntersection = rect.intersection(holeRect)

            if let context = UIGraphicsGetCurrentContext() {
                let roundedWindow = UIBezierPath(roundedRect: holeRect, cornerRadius: 15.0)
                if holeRectIntersection.intersects(rect) {
                    context.addPath(roundedWindow.cgPath)
                    context.clip()
                    context.clear(holeRectIntersection)
                    context.setFillColor(UIColor.clear.cgColor)
                    context.fill(holeRectIntersection)
                }
            }

        }
    }

layoutSubviews()中,我更新背景色并添加“窗口框架”矩形:

override func layoutSubviews() {
        super.layoutSubviews()
        backgroundColor = self.baseMoodColour
        isOpaque = false
        self.rectsArray?.removeAll()
        self.rectsArray = [dragAreaView.frame]
}

我在此处添加rect是因为layoutSubviews()更新了“窗口框架”的大小(即,在layoutSubviews()运行之后rect会发生变化)。

基本机制按预期工作,但是,如果我更改背景颜色,则抠图窗口将填充为黑色。因此,我想知道如何通过这种设置来设置背景颜色变化的动画?也就是说,我想为剪切窗口的外部区域的颜色设置动画(该窗口保持清晰)。

我尝试直接更新backgroundColor,并在UIView子类中的自定义颜色变量的访问器中也使用didSet,但是两者都导致“窗口”的相同填充。

    var baseMoodColour: UIColor {
        didSet {
            self.backgroundColor = baseMoodColour
            self.setNeedsDisplay()
        }
    }

3 个答案:

答案 0 :(得分:0)

尝试使用export default class Module extends React.Component { componentDidUpdate() { if ('component tree has been altered') { // do something } else { // do something else } } ... } ,您可以检查它here

props.children.length

答案 1 :(得分:0)

短期内的问题是,clear只是在背景颜色不透明的情况下所做的事情。只需为您的背景色设置一些透明度(甚至是一点点透明度,以至于人眼无法察觉),现在clear会在视图中形成一个洞。

例如,如果将视图的背景色设置为UIColor.green.withAlphaComponent(0.99),则代码可以正常工作。

顺便说一句,您应该删除有关UIColor.clear的行;那是一条红鲱鱼。您还应该删减关于backgroundColor的界限;您不应该将背景颜色重新绘制到您的上下文中。他们是两件事。


从长远来看,问题在于您所要做的不是在视图中打孔。您应该改用面具。这是在保持空洞的同时获取动画的唯一方法。

答案 2 :(得分:0)

根据@matt的建议(和链接的示例)回答我自己的问题,我使用CAShapeLayer做到了。我的要求中有一个额外的“障碍”,因为除了需要掩盖的观点之外,我还有其他观点。所以,我做了这样的蒙版:

func cutOutWindow() {
        // maskedBackgroundView is an additional view, inserted ONLY for the mask
        let r = self.maskedBackgroundView.bounds
        // Adjust frame for dragAreaView's border
        var dragSize = self.dragAreaView.frame.size
        var dragPosition = self.dragAreaView.frame.origin
        dragSize.width -= 6.0
        dragSize.height -= 6.0
        dragPosition.x += 3.0
        dragPosition.y += 3.0
        let r2 = CGRect(x: dragPosition.x, y: dragPosition.y, width: dragSize.width, height: dragSize.height)
        let roundedWindow = UIBezierPath(roundedRect: r2, cornerRadius: 15.0)
        let mask = CAShapeLayer()
        let path = CGMutablePath()
        path.addPath(roundedWindow.cgPath)
        path.addRect(r)
        mask.path = path
        mask.fillRule = kCAFillRuleEvenOdd
        self.maskedBackgroundView.layer.mask = mask
    }

然后我必须将颜色更改应用于maskedBackgroundView.layer.backgroundColor(即,应用于图层,而不是视图)。设置好之后,我便得到了所需的抠图,并且可以进行动画设置。感谢@matt为我指出正确的方向。