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

时间:2019-04-05 11:11:28

标签: ios xamarin.ios 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);
        }
    }

我拥有的,这正是我想要的。

enter image description here

但是我也想可以使圆圈透明而不是黑色。

我试图像这样maskOfGradientLayer.Mask = maskOfMaskLayer. 但是,maskOfMaskLayer这样无济于事!它不能像面膜一样工作。
我该怎么办?

2 个答案:

答案 0 :(得分:0)

  

但是我也想可以使圆圈透明而不是黑色。

解决方案探索版:

您还可以使用 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);

其他代码未更改。

enter image description here

  

但是我从一开始就考虑设置任何自定义图片。

解决方案二:(方向错误)

我已测试CAShapeLayer不能具有此功能来更改图像的颜色。 CAShapeLayer Class

但是,我发现UIImageView可以做到。它有一个TintColor属性。该属性来自UiView。UIView.TintColor Property

enter image description here

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);

enter image description here

正确的解决方案

很抱歉误解了真实的需求,我更新如下:

Layer.Mask = maskOfMaskLayer;

enter image description here

如果使用AddSublayer只是覆盖了图层上的图像,而Layer.Mask则是相反的效果,它仅显示覆盖该部分的背景,其余区域将为白色。 CALayer.Mask

答案 1 :(得分:0)

要做的全部是通过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;
    }
}

Final version