Ответ
Технически возможно, но крайне непрактично. CALayer — это низкоуровневый объект отрисовки без обработки событий и управления жизненным циклом.
Ограничения использования только CALayer:
- Нет обработки событий — слои не обрабатывают тапы, свайпы, жесты
- Нет автоматического управления памятью — нужно вручную контролировать retain cycles
- Нет готовых UI-компонентов — кнопки, текстовые поля, таблицы отсутствуют
- Сложная анимация — отсутствуют удобные методы анимации UIView
Базовый пример создания слоя:
class LayerOnlyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Создание и настройка слоя
let customLayer = CALayer()
customLayer.frame = CGRect(x: 50, y: 100, width: 200, height: 150)
customLayer.backgroundColor = UIColor.systemBlue.cgColor
customLayer.cornerRadius = 12
customLayer.borderWidth = 2
customLayer.borderColor = UIColor.white.cgColor
// Добавление на экран
view.layer.addSublayer(customLayer)
// Проблема: нет обработки тапов на этот слой
// Решение: добавляем gesture recognizer на view
let tapRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handleTap))
view.addGestureRecognizer(tapRecognizer)
}
@objc func handleTap(_ recognizer: UITapGestureRecognizer) {
let point = recognizer.location(in: view)
// Вручную проверяем hit test для каждого слоя
if let hitLayer = view.layer.hitTest(point) {
print("Tapped layer: (hitLayer)")
}
}
}
Практическая рекомендация:
Используйте UIView как контейнер для CALayer. UIView предоставляет:
- Автоматическое создание и управление backing layer
- Систему responder chain для обработки событий
- Удобные методы анимации (
UIView.animate) - Автоматическое обновление layout при изменении bounds
Гибридный подход (рекомендуется):
class CustomView: UIView {
override class var layerClass: AnyClass {
return CAShapeLayer.self // Кастомный тип слоя
}
override func layoutSubviews() {
super.layoutSubviews()
// Настройка кастомного слоя
if let shapeLayer = layer as? CAShapeLayer {
shapeLayer.path = UIBezierPath(roundedRect: bounds,
cornerRadius: 10).cgPath
}
}
} Ответ 18+ 🔞
А, ну ты глянь, какие вопросы задают! Можно ли на одних только CALayer интерфейс построить? Да, блядь, технически — можно, как же! Это ж просто объект отрисовки, низкоуровневый такой, фундамент. Но это будет как строить дом, используя только кирпичи и цемент, а про двери, окна, проводку и, ёпта, крышу — забыть. Можно, но жить там будет пиздец как неудобно, и каждый раз, когда дверь открыть захочешь, придётся кирпичи разбирать.
Вот смотри, в чём подвох, если только CALayer юзать:
- События — нихуя. Ты пальцем ткни — а ему похуй. Ни тапов, ни свайпов, ни жестов. Слой просто картинка, он не в курсе, что его трогают.
- Память — сам разбирайся. За ним уследить надо, чтобы он тебя не увёл в вечный цикл и приложение не накрылось медным тазом.
- Готовых штук — ноль. Хочешь кнопку? Рисуй сам. Текстовое поле? Рисуй сам. Таблицу? О, ёперный театр, это вообще отдельная песня. Всё с нуля, голыми руками.
- Анимация — мозг сломаешь. В
UIViewестьanimate(withDuration:)— красота. Тут же всё вручную, черезCABasicAnimation, и волнение ебать, чтобы всё гладко было.
Вот, на коленке, пример такого убогого подхода:
class LayerOnlyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Делаем слой, красивый такой, синий
let customLayer = CALayer()
customLayer.frame = CGRect(x: 50, y: 100, width: 200, height: 150)
customLayer.backgroundColor = UIColor.systemBlue.cgColor
customLayer.cornerRadius = 12
customLayer.borderWidth = 2
customLayer.borderColor = UIColor.white.cgColor
// Кидаем его на экран
view.layer.addSublayer(customLayer)
// А теперь, сука, проблема: как на него тапнуть?
// Придётся на всю вьюху жест вешать и потом вручную проверять, куда тыкнули
let tapRecognizer = UITapGestureRecognizer(target: self,
action: #selector(handleTap))
view.addGestureRecognizer(tapRecognizer)
}
@objc func handleTap(_ recognizer: UITapGestureRecognizer) {
let point = recognizer.location(in: view)
// И вот тут начинается цирк: проверяем для каждого слоя, попали ли в него
if let hitLayer = view.layer.hitTest(point) {
print("Тыкнули в слой: (hitLayer)") // Ура, работает! Но какой геморрой, блядь!
}
}
}
Видишь этот костыль? Это же пиздопроебищно! Каждый чих — своя подпорка.
Так что слушай сюда, умный совет: не выёбывайся. Используй UIView как нормальную, удобную обёртку для твоего CALayer. Зачем? Да потому что вьюха:
- Сама создаст и будет рулить своим слоем.
- Сама разберётся с тапами и прочими жестами (responder chain, ёпта!).
- Даст тебе красивые и простые анимации.
- Когда размер поменяется (
bounds), сама всё пересчитает и перерисует, если надо.
Вот как по-умному, гибридно сделать:
class CustomView: UIView {
// Говорим системе: "Друг, вместо стандартного слоя, дай мне кастомный, CAShapeLayer"
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override func layoutSubviews() {
super.layoutSubviews()
// А тут, когда вьюха устаканилась, настраиваем наш кастомный слой
if let shapeLayer = layer as? CAShapeLayer {
shapeLayer.path = UIBezierPath(roundedRect: bounds,
cornerRadius: 10).cgPath
}
}
}
Вот это — мощь! Ты получаешь всю мощь низкоуровневого CALayer (в данном случае CAShapeLayer) для отрисовки, но при этом живешь в уютном мире UIView со всеми его плюшками. И тебе не нужно, блядь, вручную тапы ловить и память считать. Красота, а не жизнь.