Маска слоя-маски. Основная анимация - PullRequest
0 голосов
/ 05 апреля 2019

Я глубоко в Core Animation и у меня возникли проблемы с маскировкой слоев

Я пытаюсь создать сложный слой пользовательского интерфейса с прозрачными элементами для изучения

Это представление есть и положить в 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 голосов
/ 10 апреля 2019

Все, что нужно для этого, - это изменить цвета изображения с помощью 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

0 голосов
/ 08 апреля 2019

Но я также хочу сделать прозрачный кружок вместо черного цвета.

Solution Exploration Version:

Вы также можете использовать 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 .

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

...