【问题标题】:Mask of layer mask. Core animation图层蒙版的蒙版。核心动画
【发布时间】:2019-04-23 22:48:49
【问题描述】:

我深入研究了核心动画并且在图层蒙版方面遇到了一些问题

出于学习原因,我尝试用透明的东西制作复杂的 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什么都不做!它不像面具必须做的那样工作。
我该怎么办?

【问题讨论】:

  • 似乎,Core Animation 只支持设置掩码属性的一级深度
  • 谁想知道更多。类似问题stackoverflow.com/questions/20132875/…
  • 你测试maskOfMaskLayer.FillColor = UIColor.clearColor.CGColor;而不是` maskOfMaskLayer.FillColor = UIColor.Black.CGColor;` ??
  • @mohsen 是的,我测试过。

标签: ios xamarin.ios core-animation


【解决方案1】:

但我也希望可以使圆形透明而不是黑色。

解决方案探索版:

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

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

Layer.AddSublayer(maskOfMaskLayer);

上面的代码替换为follow:

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

其他代码未更改。

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

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

我已经测试CAShapeLayer 不能有这个功能来改变图像的颜色。 CAShapeLayer Class

但是,我发现UIImageView 可以做到这一点。它有一个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

【讨论】:

  • 非常感谢您提供的优质样品。但我从一开始就考虑设置任何自定义图像。
  • @Asura 是的,您可以使用自定义图像共享示例项目。我会检查它。
  • @Asura 我已经测试了我的自定义图像。不幸的是,如果使用CAShapeLayer 无法修改此颜色。但是,如果使用UIImageView,它可以做到这一点。我已经更新了答案。
  • 然后我们失去了透明色。其实我最近解决了这个问题。而不是Layer.AddSublayer(maskOfMaskLayer); 必须是Layer.Mask = maskOfMaskLayer;
  • @Asura 很高兴你解决了它。我想我误解了你真正想要的效果。我在答案中更新了您想要的效果。 *.^
【解决方案2】:

所有需要做的就是通过 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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 1970-01-01
    • 2014-09-13
    相关资源
    最近更新 更多