Как создать продвинутые тени в Swift — iOS Swift руководство

Перевод статьи от автора Baptiste Montagliani

Спасибо CoreAnimation и CALayer, за то что мы можем с легкостью применить нестандартные тени к любым UIView, через свойство layer.

В этой статье мы увидим как создать 5 известных типов теней:

  • Отбрасываемая тень
  • Основная контактная тень
  • Контактная тень с глубиной
  • Плоская контактная тень
  • Изогнутая тень

Но сначала, посмотрим на 5 свойств слоя которые мы будем использовать для создания нестандартных теней.

shadowColor

Настройка цвета тени. Предустановленный цвет это UIColor.black.cgColor, который делает темной тень, но вы можете также установить светлый цвет для создания светящегося эффекта, или любой другой цвет.

shadowOpacity

Настройка прозрачности тени, между 0 и 1. Значение 0 означает что тень не будет видна.

shadowRadius

Настройка уровня размытия тени. Значение 0 означает что тень не будет размыта вовсе, она будет полностью плоской.

shadowOffset

Настройка позиции тени из вью. Это свойство особенно полезно когда вы хотите добавить глубины в ваш интерфейс. Значение CGSize.zero означает что тень будет совершенно выровнена с ее родительным вью.

shadowPath

Настройка формы тени. Предустановленное значение этого свойства nil которое означает что UIKit будет определять форму тени от родительной вью.

Не устанавливая shadowPath делает генерацию теней намного медленней, и так это хорошая практика устанавливать путь для этого свойства, даже для основных теней с квадратной формой.

Это свойства особенно интересно если вы хотите сделать тень нестандартной формы.

1. Отбрасываемые тени

Отбрасываемые тени это классические тени которые вы можете видеть в большинстве времени в приложениях и вебсайтах. Оно использует только свойства прозрачности, радиуса и смещения, для создания впечатляющей глубины интерфейса путем имитации высоты компонентов и их позиции от источника света.

Вы можете указать путь для этих базовых теней с помощью создания UIBezierPath из ваших границ вью.

imageView.layer.shadowRadius = 10
imageView.layer.shadowOffset = .zero
imageView.layer.shadowOpacity = 0.5
imageView.layer.shadowColor = UIColor.black.cgColor
imageView.layer.shadowPath = UIBezierPath(rect: imageView.bounds).cgPath

Вам так же понадобится установить слою свойство maskToBound в True если тень не появляется. Сделая это, вы разрешаете содержимому слоя рисовать вне границ слоя.

imageView.layer.masksToBounds = false
Отбрасываемая тень — настраиваемый цвет

Вы можете установить не нулевое смещение позиции тени для настройки позиции тени. Помните, что для обеспечения гладкости интерфейса обычно лучше установить аналогичное смещение между вью, поскольку предполагается, что тень устанавливается в зависимости от ориентации света.

imageView.layer.shadowOffset = CGSize(width: 0, height: 10)
Отбрасываемая тень — настраиваемое смещение

Свойство shadowRadius позволит вам настроить применимое размытие для тени. Здесь пример с радиусом 1, 10 и 50

Отбрасываемая тень — настраиваемый радиус

Если вы хотите больше узнать больше как определить логику возвышения к теням вашего приложения, есть хорошая документация на material.io. Это было разработано для тем приложения с материальной разработкой, но это все еще актуальная информация и практика которая может быть использована в любом приложении или вебсайте, включая приложения iOS.

Диаграмма значений возвышения по умолчанию — material.io

2. Контактная тень

Контактная тень описываем тип тени которую вы видите когда объект контактирует в поверхностью или возле нее.

Пример контактной тени

Для добавления настраиваемой контактной тени на вью, нам понадобится создать путь формы которая нам необходима: плоский овал.

let size: CGFloat = 20
let distance: CGFloat = 0
let rect = CGRect(
    x: -size,
    y: imageView.frame.height - (size * 0.4) + distance,
    width: imageView.frame.width + size * 2,
    height: size
)
imageView.layer.shadowColor = UIColor.black.cgColor
imageView.layer.shadowRadius = 7
imageView.layer.shadowOpacity = 0.5
imageView.layer.shadowPath = UIBezierPath(ovalIn: rect).cgPath

Отрицательный размер сделает тень более маленькой чем изображение. И дистанция больше 0 сделает вью на расстоянии о других вью.

Контактная тень

3. Контактная тень с глубиной

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

Для создания этого эффекта, вам нужно в ручную создать  shadowPath представляющий настраиваемую форму. Смотрите код ниже:

let scale = CGSize(width: 1.25, height: 0.5)
let offsetX: CGFloat = 0

let shadowPath = UIBezierPath()
shadowPath.move(to:
    CGPoint(
        x: 0,
        y: imageView.frame.height
    )
)
shadowPath.addLine(to:
    CGPoint(
        x: imageView.frame.width,
        y: imageView.frame.height
    )
)
shadowPath.addLine(to:
    CGPoint(
        x: imageView.frame.width * scale.width + offsetX,
        y: imageView.frame.height * (1 + scale.height)
    )
)
shadowPath.addLine(to:
    CGPoint(
        x: imageView.frame.width * (1 - scale.width) + offsetX,
        y: imageView.frame.height * (1 + scale.height)
    )
)

Вы можете изменять значение размера для создания более маленьких или больших теней.

Если вы установите отрицательное значение для scale.height, тень появится за вью, это изменит глубина направления.

Со свойством offset вы можете горизонтально двигать источник света, таким образом скручивая тень, чтобы она выглядела соответственно источнику света.

Контактная тень с настраиваемой глубиной

4.  Плоская контактная тень

Этот эффект тени особенно важен в современном дизайне. Это становится все более и более популярным, поскольку плоский дизайн становится нормой.

Для этого эффекта мы будем использовать кодовую базу предыдущего эффекта «Контактная тень с глубиной». На самом деле нам нужно только добавить новое свойство offsetY, чтобы заставить работать наш плоский эффект, и, конечно же, уменьшить радиус тени.

let scale = CGSize(width: 1.5, height: 1.5)
let offset = CGPoint(x: imageView.frame.width, y: -imageView.frame.height)

let shadowPath = UIBezierPath()
shadowPath.move(to:
    CGPoint(
        x: 0,
        y: imageView.frame.height + (copysign(1, scale.height) * copysign(1, offset.x) == 1 ? 0 : offset.y)
    )
)
shadowPath.addLine(to:
    CGPoint(
        x: imageView.frame.width,
        y: imageView.frame.height + (copysign(1, scale.height) * copysign(1, offset.x) == -1 ? 0 : offset.y)
    )
)
shadowPath.addLine(to:
    CGPoint(
        x: imageView.frame.width * scale.width + offset.x,
        y: imageView.frame.height * (1 + scale.height) + offset.y
    )
)
shadowPath.addLine(to:
    CGPoint(
        x: imageView.frame.width * (1 - scale.width) + offset.x,
        y: imageView.frame.height * (1 + scale.height) + offset.y
    )
)
imageView.layer.shadowPath = shadowPath.cgPath
imageView.layer.shadowRadius = 0
imageView.layer.shadowOffset = .zero
imageView.layer.shadowOpacity = 0.2
imageView.layer.shadowColor = UIColor.black.cgColor
Плоская контактная тень

5. Изогнутые тени

Для данного типа теней мы опять используем свойство shadowPath. Вы можете немного поиграть со значениями ниже, чтобы создать плавную тень, которая будет соответствовать потребностям вашего дизайна.

Чтобы тень выглядела изогнутой, мы используем функцию addCurve из UIBezierPath. Путем установки свойства curve вы можете настроить интенсивность изгибания. Вы можете напрямую использовать свойство слоя shadowOffest, чтобы настроить его в соответствии с вашим вью.

let curve: CGFloat = 100

let shadowPath = UIBezierPath()
shadowPath.move(to: CGPoint.zero)
shadowPath.addLine(to: CGPoint(
    x: imageView.frame.width,
    y: 0
))
shadowPath.addLine(to: CGPoint(
    x: imageView.frame.width,
    y: imageView.frame.height + curve
))
shadowPath.addCurve(
    to: CGPoint(
        x: 0,
        y: imageView.frame.height + curve
    ),
    controlPoint1: CGPoint(
        x: imageView.frame.width,
        y: imageView.frame.height
    ),
    controlPoint2: CGPoint(
        x: 0,
        y: imageView.frame.height
    )
)
imageView.layer.shadowPath = shadowPath.cgPath
imageView.layer.shadowRadius = 10
imageView.layer.shadowOffset = CGSize(width: 0, height: 10)
imageView.layer.shadowOpacity = 0.5
imageView.layer.shadowColor = UIColor.black.cgColor
Изогнутые тени

Резюме

Теперь вы знаете как добавить в ваше приложение глубины с помощью добавления красивых и полностью настраиваемых теней с CALayer, и вы выучили как создавать базовые и продвинутые тени со свойством shadowPath. Здесь короткое резюме из 5 типов теней которых мы видели в этой статье.

  • Отбрасываемая тень
  • Основная контактная тень
  • Контактная тень с глубиной
  • Плоская контактная тень
  • Изогнутая тень