CALayer, или как закруглить углы, сделать тень и градиент на Swift

В данной статье мы рассмотрим свойство UIView — layer, то есть слой. Это класс CALayer, который в свою очередь имеет ряд весьма полезных свойств, регулируя которые можно изменить внешний вид любого UIView. Самое популярное применение свойств CALayer  — это закругление углов (cornerRadius) и тень (shadow), а также рисование градиента (gradient). Как Вы помните, UIView — это базовый класс для всего, что отображается на экране — кнопок, картинок, переключателей и т.д. А это означает, что все свойства, которые мы будем менять в данной статье можно изменить у любого элемента в интерфейсе пользователя

.CALayer_proSwift_ru_9nchz

 Мы создадим проект, в котором сделаем (сверху вниз по картинке): градиент, закругление углов с выделением границы, и закругление углов и тень вокруг кнопки.

Подготовка

Для начала создайте проект в Xcode Single View Application, перейдите в Storyboard и добавьте на контроллер три элемента: два View и одну кнопку. Добавьте цвета для фона контроллера, двух волов View и кнопки, что было удобно с ними работать и различать их. Далее создайте два файла с классами, которые будут наследниками класса UIView. Я назвал классы BlueView и LogoView.

//
// proSwift.ru
//
// BlueView.Swift

import UIKit

@IBDesignable class BlueView: UIView {

}
//
// proSwift.ru
//
// LogoView.Swift

import UIKit

@IBDesignable class LogoView: UIView {

}

Инстркуция @IBDesignable добавлена для того, чтобы просматривать изменения отрисовки для UIView и его подклассов прямо в Storyboard без компиляции приложения и запуска его на симуляторе или реальном устройстве.

Далее каждому из добавленных ранее View в Identity Inspector установите соответствующие классы.

CALayer_proSwift_ru_t1x8hCALayer_proSwift_ru_t1x8h

Далее создайте аутлеты для элементов интерфейса.

//
// proSwift.ru
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var blueView: BlueView!
    @IBOutlet weak var orangeButton: UIButton!
    @IBOutlet weak var logoView: LogoView!

}

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

CALayer_proSwift_ru_tthhj

Как вы заметили, у меня в  LogoView красуется картинка. У вас ее не будет. Я ниже напишу как добавить картину в LogoView. А пока можете приготовить любую квадратную картинку, над которой вы будете ставить эксперименты. Я приведу код файла LogoView, в котором я сделал возможность выбора картинки непосредственно в Interface Builder, т.е. в Storyboard. Именно поэтому в нем реализовано  такое количество методов. Однако если внимательно посмотреть, то все вполне логично:

//
// proSwift.ru
//

import UIKit

@IBDesignable class LogoView: UIView {
    
    let imageView = UIImageView()
    
@IBInspectable var image: UIImage? {
        didSet {
            addImage()
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        setup()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setup()
    }
    
    func setup () {
        imageView.frame = CGRectMake(0, 0, 240, 240)
        imageView.contentMode = .ScaleAspectFit
        addSubview(imageView)
    }
    
    func addImage() {
        imageView.image = image
    }
}

Методы awakeFromNib() и prepareForInterfaceBuilder() запускаются единожды: первый при запуске приложения и загрузки UIView из Storybord, второй при переходе в Storyboard  для отрисовки изменений непосредственно на сцене Interface Builder. Для нашего LogoView я добавил свойство  imageView: UIImgeView для отображения картинки, и свойство image для выбора картинки, которое будет отображать imageView. Метод setup() запускает настройку для imageView.

Свойство image я пометил инструкцией @IBInspectable и установил наблюдателя свойства didSet. Тип @IBInspectable свойства должен быть явно указан, как в нашем случае  — мы сказали что оно будет опционалом UIImage (то есть явно указали тип после двоеточия). А при помощи наблюдателя свойства мы устанавливаем картинку в UIImageView.

Вы спросите — зачем все эти сложности? А я вам отвечу — для того, чтобы менять картинку прямо из Storyboard. После всех наших изменений в Storyboard можно обнаружить следующие изменения:

CALayer_proSwift_ru_gxoet

При выборе нашего LogoView в атрибут инспекторе появилась настройка Image в которой можно выбрать любую картинку, которую вы добавите в проект. Добавьте картинку или несколько в проект, и после этого выберите ее из выпадающего списка. Картинка отрисуется прямо на сцене  Interface Builder.

Давайте подобные настройки сделаем для blueView. В класс BluewView добавьте следующее:

//
// proSwift.ru
//

import UIKit


@IBDesignable class BlueView: UIView {
    
    // 1
    let gradientLayer = CAGradientLayer()
    
    // 2
    @IBInspectable var startColor: UIColor = UIColor.blackColor() {
        didSet {
            gradientSetup()
        }
    }

    // 3
    @IBInspectable var midColor: UIColor = UIColor.blueColor() {
        didSet {
            gradientSetup()
        }
    }
    
    // 4
    @IBInspectable var endColor: UIColor = UIColor.whiteColor() {
        didSet {
            gradientSetup()
        }
    }
    
    // 5   
    override func awakeFromNib() {
        super.awakeFromNib()
        setup()
    }
    
    // 6
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setup()
    }
    
    // 7
    private func setup() {
        layer.addSublayer(gradientLayer)
        gradientSetup()
    }
    
    // 8
    private func gradientSetup() {
 
    }

    // 9
    override func layoutSubviews() {
        gradientLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))
    }
}

Давайте разберем по пунктам, но для начала, также как и классу LogoView, установим директиву  @IBDesignable

  1. Для нашего класса BlueView мы добавали свойство gradienLayer типа CAGradientLayer и использовали стандартный инициализатор. Задавать свойства для градиенты мы будем именно этому слою, а потом добавим его в иерархию слоев BlueView
  2. Свойство, в котором мы будем задавать стартовый цвет для градиента.
  3. Свойство, в котором мы будем задавать средний цвет для градиента.
  4. Свойство, в котором мы будем задавать конечный цвет для градиента.
  5. Метод, который вызывается единожды при загрузке View из Storyboard
  6. Метод, который вызывается единожды для отрисовки непосредственно в  Storyboard
  7. В этом методе мы добавляем слой градиента в иерархию слоев BlueView и вызываем метод, в котором будем устанавливать настройки для градиента
  8. Непосредственно, метод, в котором мы и будем задавать настройки отображения градиента
  9. Как и в случае с LogoView . В нашем случае это удобнее всего в методе layoutSubviews(), т.к. размер frame у нас насчитывается из размеров BlueView, в котором он отображается. А при выполнении этого метода размеры BlueView уже известны.

Свойства 2-4 помечены директивой @IBInspectable для отображения в списке Attributes Inspector. Это дает нам возможность выбора цветов мышкой прямо в Interface Builder.

CALayer_proSwift_ru_9zyag

Вся подготовительная работа выполнена и можно приступить непосредственно к настройки параметров отображения.

Следующая часть: CALayer- градиент: CAGradientLayer

 

Ссылка проекта на Github

https://github.com/Ironrnd/CALayer_proSwift_ru

Добавить комментарий

Ваш адрес email не будет опубликован.

*

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.