Нарисуйте линию на UIView с помощью CAGradientLayer в качестве резервного хранилища

Я создал подкласс UIView, который использует CAGradientLayer для своего слоя. Это работает нормально. Теперь я хочу нарисовать линию в конце градиента (используется как разделитель). Я подумал, что могу использовать для этого метод drawRect:

public class GradientView : UIView
{
    // accessors
    private CAGradientLayer gradientLayer {
        // read-only
        get { return (CAGradientLayer)this.Layer; }
    }

    public CGColor[] Colors {
        // set the colors of the gradient layer
        get { return this.gradientLayer.Colors; }
        set { this.gradientLayer.Colors = value; }
    }

    [Export ("layerClass")]
    public static Class LayerClass ()
    {
        // use a different Core Animation layer for its backing store
        // normally a CALayer is used for a UIView
        return new Class (typeof(CAGradientLayer));
    }

    public override void Draw (RectangleF rect)
    {

        PointF pointA = new PointF (0, rect.Height);
        PointF pointB = new PointF (rect.Width, rect.Height);
        CAShapeLayer line = new CAShapeLayer ();
        UIBezierPath linePath = new UIBezierPath ();
        linePath.MoveTo (pointA);
        linePath.AddLineTo(pointB);
        line.Path = linePath.CGPath;
        line.FillColor = null;
        line.Opacity = 1.0f;
        line.StrokeColor = UIColor.Black.CGColor;

        this.gradientLayer.AddSublayer (line);

        base.Draw (rect);
    }
}

Но у меня черный фон. Могу ли я использовать drawRect для этого? Или как мне добавить строку на него?

Я использую C# в качестве языка, но вы также можете предоставить свое решение на Objective-C. Auto Layout определяет размер GradientView, и мое старое решение также адаптировалось к изменениям ориентации.

Изменить:

Я попробовал то, что сказал Сирил:

public class GradientView : UIView
{
    // accessors
    private CAShapeLayer line;

    private CAGradientLayer gradientLayer {
        // read-only
        get { return (CAGradientLayer)this.Layer; }
    }

    public CGColor[] Colors {
        // set the colors of the gradient layer
        get { return this.gradientLayer.Colors; }
        set { this.gradientLayer.Colors = value; }
    }

    public GradientView()
    {
        PointF pointA = new PointF (0, this.Bounds.Height);
        PointF pointB = new PointF (this.Bounds.Width, this.Bounds.Height);
        line = new CAShapeLayer ();
        UIBezierPath linePath = new UIBezierPath ();
        linePath.MoveTo (pointA);
        linePath.AddLineTo(pointB);
        line.Path = linePath.CGPath;
        line.FillColor = null;
        line.Opacity = 1.0f;
        line.StrokeColor = UIColor.Black.CGColor;
        line.LineWidth = 1.0f;

        this.gradientLayer.AddSublayer (line);
    }

    [Export ("layerClass")]
    public static Class LayerClass ()
    {
        // use a different Core Animation layer for its backing store
        // normally a CALayer is used for a UIView
        return new Class (typeof(CAGradientLayer));
    }

    public override void LayoutSubviews ()
    {
        PointF pointA = new PointF (0, this.Bounds.Height-2);
        PointF pointB = new PointF (this.Bounds.Width, this.Bounds.Height-2);
        UIBezierPath linePath = new UIBezierPath ();
        linePath.MoveTo (pointA);
        linePath.AddLineTo(pointB);

        line.Path = linePath.CGPath;

        base.LayoutSubviews ();
    }
}

Кажется, это делает то, что я хочу, за исключением того, что линия не тонкая. CAShapeLayer не подходит для этого?

Решение:

Конечно, можно было бы использовать CAShapeLayer, но если мне нужно что-то настроить в drawRect, то я полностью провожу там свою линию. Теперь решение для меня выглядит следующим образом:

public class GradientView : UIView
{
    // accessors
    private CAShapeLayer line;

    private CAGradientLayer gradientLayer {
        // read-only
        get { return (CAGradientLayer)this.Layer; }
    }

    public CGColor[] Colors {
        // set the colors of the gradient layer
        get { return this.gradientLayer.Colors; }
        set { this.gradientLayer.Colors = value; }
    }

    public GradientView()
    {
        this.BackgroundColor = UIColor.Clear;
    }

    [Export ("layerClass")]
    public static Class LayerClass ()
    {
        // use a different Core Animation layer for its backing store
        // normally a CALayer is used for a UIView
        return new Class (typeof(CAGradientLayer));
    }

    public override void Draw (RectangleF rect)
    {
        base.Draw (rect);

        // get graphics context
        CGContext context = UIGraphics.GetCurrentContext ();

        // start point
        context.MoveTo (0, rect.Height);

        // end point
        context.AddLineToPoint (rect.Width, rect.Height);

        context.SetLineWidth (1.0f);

        context.SetShouldAntialias(false);

        // draw the path
        context.DrawPath (CGPathDrawingMode.Stroke);
    }

person testing    schedule 09.12.2014    source источник


Ответы (1)


Использование CAGradientLayer в качестве резервного слоя вашего представления не мешает вам добавить еще один CAShapeLayer внутри вашего представления при инициализации. Затем вы можете использовать этот слой формы для рисования прямой линии, соответствующим образом установив его свойство path (и пересчитывая его каждый раз, когда границы меняются, в -layoutSubviews, чтобы правильно реагировать на изменения ориентации/макета).

person Cyrille    schedule 09.12.2014
comment
Спасибо за ваш ответ. Я попробовал то, что вы сказали, и это работает. Однако один вопрос: как я могу нарисовать тонкую харлайн с помощью CAShapeLayer? - person testing; 09.12.2014
comment
Многие вопросы по SO уже касаются этой проблемы: .com/questions/21515451/draw-a-line-with-a-calayer, stackoverflow.com/questions/21515451/draw-a-line-with-a-calayer - person Cyrille; 09.12.2014
comment
Другой вопрос: почему UIView получает черный фон, когда я реализую drawRect? Кажется, я не могу отключить сглаживание без получения текущего графического контекста (например, отключить псевдоним для UIBezierPath). Но, насколько я знаю, текущий графический контекст доступен только в drawRect, что я снова не могу реализовать. - person testing; 09.12.2014
comment
Опять же, это еще один вопрос: stackoverflow.com/questions/19555889/black -background-in-uiview - person Cyrille; 09.12.2014
comment
Установка чистого цвета фона и отключение сглаживания, кажется, работает. Еще раз спасибо. - person testing; 09.12.2014