图层蒙版的蒙版。核心动画

Mask of layer mask. Core animation

我深入研究了 Core Animation 并且在图层蒙版方面遇到了一些问题

出于研究原因,我尝试制作一个复杂的 UI 透明层

此视图已并放入ViewController

public class TestView : UIView
    {
        public TestView()
        {
            Layer.Delegate = this;
            Frame = new CGRect(100f,200f, 100f, 100f);
        }

        public override void LayoutSublayersOfLayer(CALayer layer)
        {
            base.LayoutSublayersOfLayer(layer);

            var bounds = Bounds;
            var circleFrame = new CGRect(20, 20, 60, 60);
            var imageFrame = new CGRect(30, 30, 40, 40);

            Layer.BorderWidth = 5;
            Layer.BorderColor = UIColor.Red.CGColor;
            Layer.CornerRadius = 4;

            var gradientLayer = new CAGradientLayer();
            gradientLayer.Colors = new[] { UIColor.Green.CGColor, UIColor.Red.CGColor };
            gradientLayer.Frame = bounds;
            Layer.AddSublayer(gradientLayer);

            var maskOfGradientLayer = new CAShapeLayer();
            var path = UIBezierPath.FromRoundedRect(circleFrame, 30);
            path.UsesEvenOddFillRule = true;
            maskOfGradientLayer.Path = path.CGPath;
            maskOfGradientLayer.FillRule = CAShapeLayer.FillRuleEvenOdd;
            maskOfGradientLayer.FillColor = UIColor.Black.CGColor;
            maskOfGradientLayer.Frame = bounds;
            gradientLayer.Mask = maskOfGradientLayer;

            var maskOfMaskLayer = new CAShapeLayer();
            maskOfMaskLayer.Frame = imageFrame;
            maskOfMaskLayer.FillColor = UIColor.Black.CGColor;
            maskOfMaskLayer.Contents = Bundles.ImageOff.CGImage;

            Layer.AddSublayer(maskOfMaskLayer);
        }
    }

我有,这正是我想要的。

不过我也想把圆形做成透明的而不是黑色。

我试过这样做maskOfGradientLayer.Mask = maskOfMaskLayer. 但是这样maskOfMaskLayer什么都不做!它不像面具必须做的那样工作。
我该怎么办?

But I also want can to make transparent in circle instead black color.

解决方案探索版:

你也可以用UIBezierPath画你想要的,设置为maskOfMaskLayer:

var maskOfMaskLayer = new CAShapeLayer();
maskOfMaskLayer.Frame = imageFrame;
maskOfMaskLayer.FillColor = UIColor.Black.CGColor;
maskOfMaskLayer.Contents = Bundles.ImageOff.CGImage;

Layer.AddSublayer(maskOfMaskLayer);

上行代码替换为:

UIBezierPath offCirclePath = new UIBezierPath();

// draw an arc
offCirclePath.AddArc(new CGPoint(50, 50), circleFrame.Width / 3, (nfloat)(1.75 * Math.PI), (nfloat)(1.25 * Math.PI), true);

//draw a line
offCirclePath.MoveTo(new CGPoint(50, 30));
offCirclePath.AddLineTo(new CGPoint(50, 45));

//set to maskOfMaskLayer 
var maskOfMaskLayer = new CAShapeLayer();
maskOfMaskLayer.FillColor = UIColor.Clear.CGColor;
maskOfMaskLayer.Path = offCirclePath.CGPath;
maskOfMaskLayer.LineWidth = 5;
maskOfMaskLayer.StrokeColor = UIColor.White.CGColor;
maskOfMaskLayer.LineCap = new NSString("round");

Layer.AddSublayer(maskOfMaskLayer);

其他代码未更改。

But I from starts thought about setting any custom image.

方案二:(方向错误)

我测试过CAShapeLayer不能有这个从图片变色的功能。 CAShapeLayer Class

但是,我发现 UIImageView Can do that.There 是 it.This 的 TintColor 属性 属性 来自 UiView。UIView.TintColor Property

var maskOfMaskLayer = new CAShapeLayer();
maskOfMaskLayer.Frame = imageFrame;
maskOfMaskLayer.FillColor = UIColor.Black.CGColor;
maskOfMaskLayer.Contents = Bundles.ImageOff.CGImage;

Layer.AddSublayer(maskOfMaskLayer);

更改为:

UIImageView imageView = new UIImageView();
imageView.Frame = imageFrame;
imageView.Image = Bundles.ImageOff;
imageView.TintColor = UIColor.White;

AddSubview(imageView);

正确解

抱歉误解了真正想要的效果,更新如下:

Layer.Mask = maskOfMaskLayer;

如果你用AddSublayer只是把你的图像覆盖在Layer上,Layer.Mask是相反的效果,它只显示覆盖部分的背景,其余区域将被覆盖白色.CALayer.Mask

所有需要做的就是通过 Core Graphics 反转图像颜色,任何颜色透明,透明任何颜色。在这种情况下,黑色就足够了

public static UIImage GetRevertImage(UIImage image, CGRect rect, CGRect cropFrame)
{
    UIGraphics.BeginImageContextWithOptions(rect.Size, false, 1);
    UIColor.Black.SetColor();
    UIGraphics.RectFill(rect);
    image.Draw(cropFrame, CGBlendMode.DestinationOut, 1);

    var newImage = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    return newImage;
}

并将遮罩层的遮罩设置为父层

Layer.Mask = maskOfMaskLayer;

代码的最终版本:

public class TestView : UIView
{
    public TestView()
    {
        Layer.Delegate = this;
        Frame = new CGRect(50f, 50f, 100f, 100f);
    }

    public override void LayoutSublayersOfLayer(CALayer layer)
    {
        base.LayoutSublayersOfLayer(layer);

        var bounds = Bounds;
        var circleFrame = new CGRect(20, 20, 60, 60);
        var imageFrame = new CGRect(30, 30, 40, 40);

        Layer.BorderWidth = 5;
        Layer.BorderColor = UIColor.Red.CGColor;
        Layer.CornerRadius = 4;
        Layer.MasksToBounds = true;

        var gradientLayer = new CAGradientLayer();
        gradientLayer.Colors = new[] {UIColor.Green.CGColor, UIColor.Red.CGColor};
        gradientLayer.Frame = bounds;
        Layer.AddSublayer(gradientLayer);

        var maskOfGradientLayer = new CAShapeLayer();
        var path = UIBezierPath.FromRoundedRect(circleFrame, 30);
        path.UsesEvenOddFillRule = true;
        maskOfGradientLayer.Path = path.CGPath;
        maskOfGradientLayer.FillRule = CAShapeLayer.FillRuleEvenOdd;
        maskOfGradientLayer.FillColor = UIColor.Black.CGColor;
        maskOfGradientLayer.Frame = bounds;
        gradientLayer.Mask = maskOfGradientLayer;

        var maskOfMaskLayer = new CALayer();
        maskOfMaskLayer.Frame = bounds;
        var image = UIImage.FromBundle("Turn");
        var reversedImage = GetReverseImage(image, bounds, imageFrame);
        maskOfMaskLayer.Contents = reversedImage.CGImage;

        Layer.Mask = maskOfMaskLayer;
    }

    private static UIImage GetReverseImage(UIImage image, CGRect rect, CGRect cropFrame)
    {
        UIGraphics.BeginImageContextWithOptions(rect.Size, false, 1);
        UIColor.Black.SetColor();
        UIGraphics.RectFill(rect);
        image.Draw(cropFrame, CGBlendMode.DestinationOut, 1);
        var newImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();

        return newImage;
    }
}