Объедините различные классы UIView - PullRequest
0 голосов
/ 13 января 2019

Например, у меня есть подклассы UIView, такие как RoundedView, ShadowedView, GradientView, и можно объединить их в один величайший класс. Но поскольку у нас нет множественного наследования в смысле C ++ и мы не хотим иерархии этих классов, каков наилучший подход для этого? Я рассматриваю расширение протокола, но так как я новичок в Swift, я могу испортить дизайн.

UPD. Спасибо @Robert Dresler за его очень наглядный ответ. Вот что я придумала. Но есть ли какие-либо улучшения в реализации конкретного класса, потому что всегда будет присутствовать шаблонный код.

protocol Gradientable where Self: UIView {
    var startColor: UIColor { get set }
    var endColor: UIColor { get set }
    func updateColors()
}

extension Gradientable {

    var gradientLayer: CAGradientLayer {
        return layer as! CAGradientLayer
    }

    func updateColors() {
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
    }
}

protocol CornersRoundable where Self: UIView {
    var cornerRadius: CGFloat { get set }
    func roundCorners()
}

extension CornersRoundable {
    func roundCorners() {
        self.layer.cornerRadius = cornerRadius
        self.layer.masksToBounds = true
    }
}

@IBDesignable
class SuperbView : UIView, Gradientable, CornersRoundable {

    @IBInspectable var cornerRadius: CGFloat = 6.0 {
        didSet { roundCorners() }
    }

    @IBInspectable var startColor: UIColor = .white {
        didSet { updateColors() }
    }

    @IBInspectable var endColor: UIColor = .black {
        didSet { updateColors() }
    }

    override class var layerClass: AnyClass {
        return CAGradientLayer.self
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        roundCorners()
        updateColors()
    }
}

1 Ответ

0 голосов
/ 13 января 2019

Учитывая расширение протокола, это очень хороший момент. Итак, давайте посмотрим на это.


Объявление

Давайте начнем с простого объявления протокола

protocol Colorable where Self: UIView {
}

мы используем ключевое слово protocol, следующее за именем протокола. Затем, когда мы хотим, мы можем ограничить наш протокол конкретными типами, это делает это where Self: Type. Допустим, мы ограничиваем его UIView. Теперь наш протокол можно использовать для типа UIView (и для всех унаследованных классов).

Теперь давайте объявим некоторую переменную

protocol Colorable where Self: UIView {
    var mainColor: UIColor { get set }
}

... мы заявляем, что каждое представление, соответствующее протоколу Colorable, должно иметь объявленную переменную mainColor.


Осуществление

Теперь, как реализовать наш протокол? В Swift принято объявлять протокол в расширении, но вы также можете объявить его сразу после объявления типа

extension MyView: Colorable {}

или

class MyView: UIView, Colorable {}

Ясно? Теперь мы должны добавить все необходимые вещи из декларации протокола. Поскольку мы объявили только одну переменную, давайте поместим ее и дадим ей значение

class MyView: UIView {
    var mainColor: UIColor = .black
}

Добавление функций

Все ли еще ясно? Хорошо, давайте продолжим с добавлением метода в наш протокол

protocol Colorable where Self: UIView {
    var mainColor: UIColor { get set }
    func doSomethingWithColor()
}

теперь мы должны объявить этот метод внутри нашего подкласса представления, или мы можем объявить этот метод внутри расширения протокола. Поскольку мы знаем, что этот протокол также требует объявления переменной mainColor, мы можем работать с ним

extension Colorable {
    func doSomethingWithColor() {
        backgroundColor = mainColor
    }
}

и тогда мы можем вызвать это в любом представлении, которое соответствует этому протоколу

let myView = MyView()
myView.doSomethingWithColor()

Методы с общими ограничениями

Теперь последняя часть. Допустим, у нас есть UIViewController, который включает в себя три представления разных типов и все соответствует протоколу Colorable. Это позволяет нам использовать общее ограничение на метод. Это ограничение объявляет тип, скажем, T, который соответствует протоколу. И этот тип мы можем использовать в качестве параметра метода, и мы будем на 100% уверены, что мы передаем представление, которое имеет именно то, что нам нужно, в нашем случае переменную mainColor

func changeBorderColorOf<T: Colorable>(_ view: T) {
    view.layer.borderColor = view.mainColor.cgColor
}

теперь мы можем вызвать этот метод и в качестве параметра мы можем передать любой UIView, который соответствует нашему протоколу

let myView = MyView()
changeBorderColorOf(myView)

Обобщения - большая тема, поэтому я надеюсь, что это поможет вам начать! ; -)

...