Добрый день всем. Подскажите, как сделать два эффекта на одном Виде.
Я пробовал это сделать через CALayer. Но этот метод не работает!
// Create UIView.
let testView = UIView()
testView.backgroundColor = UIColor.gray
testView.layer.borderWidth = 1
testView.translatesAutoresizingMaskIntoConstraints = false
// Create layer with shadow.
let shadowUp = createShadowDown(buttonMenu)
// Add layer with shadow to UIView.
testView.layer.insertSublayer(layerOne, at: 0)
// Method create shadow.
func createShadowUp(_ size: UIView) -> CALayer {
let layer = CALayer()
layer.frame = size.bounds
layer.shadowColor = UIColor.red.cgColor
layer.shadowOpacity = 1
layer.shadowRadius = 10
layer.shadowOffset = CGSize(width: 0, height: 20)
return layer
}
Второй способ работает, но две тени сделать нельзя! Здесь он, скорее всего, перезаписывает значения.
// Create UIView.
let testView = UIView()
testView.backgroundColor = UIColor.gray
testView.layer.borderWidth = 1
testView.translatesAutoresizingMaskIntoConstraints = false
// Create shadow.
createShadowTest(testView))
// Method create shadow.
func createShadowTest(_ view: UIView) {
view.layer.shadowColor = UIColor.red.cgColor
view.layer.shadowOpacity = 1
view.layer.shadowRadius = 10
view.layer.shadowOffset = CGSize(width: 0, height: 20)
}
Неужели нельзя добавить две тени для одного View?
Я посмотрел решения на этом сайте, но они не работают! Например здесь - Добавление нескольких теней скрывает цвет фона и текст UIButton
// Create UIView.
let testView = UIView()
testView.backgroundColor = UIColor.gray
testView.layer.borderWidth = 1
testView.translatesAutoresizingMaskIntoConstraints = false
// Create shadow.
addDropShadow(testView))
// Method create shadow.
func addDropShadow() {
let topLayer = createShadowLayer(color: .red, offset: CGSize(width: 0, height: -20))
let bottomLayer = createShadowLayer(color: .green, offset: CGSize(width: 0, height: 20))
self.testView.layer.insertSublayer(topLayer, at: 0)
self.testView.layer.insertSublayer(bottomLayer, at: 1)
}
func createShadowLayer(color: UIColor, offset: CGSize) -> CALayer {
let shadowLayer = CALayer()
shadowLayer.masksToBounds = false
shadowLayer.shadowColor = color.cgColor
shadowLayer.shadowOpacity = 1
shadowLayer.shadowOffset = offset
shadowLayer.shadowRadius = 10
shadowLayer.shouldRasterize = true
shadowLayer.shadowPath = UIBezierPath(roundedRect: testView.bounds, cornerRadius: 10).cgPath
return shadowLayer
}
Здесь есть две проблемы:
UIView
был создан как UIView()
. Это значит, что это frame.size
и есть .zero
.
Более тонкая проблема заключается в том, что вы устанавливаете shadowPath
, используя текущий bounds
. Но если рамка представления впоследствии будет изменена (вручную или с помощью ограничений макета), shadowPath
не будет автоматически обновлять свой путь, чтобы отразить новый размер.
Я бы предложил переместить эту shadowPath
логику настройки в подкласс UIView
, чтобы при изменении размера представления соответствующие значения shadowPath
могли обновляться (в его методе layoutSubviews
):
class ViewWithShadows: UIView {
private var shadowLayers: [CALayer] = []
override func layoutSubviews() {
super.layoutSubviews()
let path = shadowPath.cgPath
for shadowLayer in shadowLayers {
shadowLayer.shadowPath = path
}
}
func addShadowLayer(color: UIColor, offset: CGSize = .zero, radius: CGFloat = 10) {
let sublayer = shadowLayer(color: color, offset: offset, radius: radius)
layer.addSublayer(sublayer)
shadowLayers.append(sublayer)
}
func insertShadowLayer(color: UIColor, offset: CGSize = .zero, radius: CGFloat = 10, at index: UInt32) {
let sublayer = shadowLayer(color: color, offset: offset, radius: radius)
layer.insertSublayer(sublayer, at: index)
shadowLayers.append(sublayer)
}
}
private extension ViewWithShadows {
var shadowPath: UIBezierPath {
UIBezierPath(roundedRect: bounds, cornerRadius: 10)
}
// Method create shadow.
func shadowLayer(color: UIColor, offset: CGSize, radius: CGFloat) -> CALayer {
let shadowLayer = CALayer()
shadowLayer.masksToBounds = false
shadowLayer.shadowColor = color.cgColor
shadowLayer.shadowOpacity = 1
shadowLayer.shadowOffset = offset
shadowLayer.shadowRadius = radius
shadowLayer.shadowPath = shadowPath.cgPath
return shadowLayer
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addTwoShadowView()
}
func addTwoShadowView() {
// Create UIView.
let subview = ViewWithShadows()
subview.backgroundColor = .gray
subview.layer.borderWidth = 1
subview.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(subview)
NSLayoutConstraint.activate([
subview.centerXAnchor.constraint(equalTo: view.centerXAnchor),
subview.centerYAnchor.constraint(equalTo: view.centerYAnchor),
subview.widthAnchor.constraint(equalToConstant: 100),
subview.heightAnchor.constraint(equalToConstant: 100)
])
subview.insertShadowLayer(color: .red, offset: CGSize(width: 0, height: -20), at: 0)
subview.insertShadowLayer(color: .green, offset: CGSize(width: 0, height: 20), at: 1)
}
}
В любом случае это дает:
Есть много разных способов решить эту проблему, и это только один. Но, надеюсь, это иллюстрирует идею. Просто убедитесь, что ваш теневой путь обновляется при изменении вида bounds
.
Лично я был бы склонен не пытаться добавлять разные слои, а просто иметь два вида, каждый с тенью, примененной к его основному layer
, и исключить shadowPath
. Это устраняет логику, связанную с «настройкой shadowPath
при изменении bounds
», будет предложена более изящная анимация в случае изменения bounds
представления (если вам нужно это сделать) и т. д.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addTwoShadowViews()
}
}
private extension ViewController {
func shadowView(color: UIColor, offset: CGSize, radius: CGFloat = 10) -> UIView {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .gray
view.layer.masksToBounds = false
view.layer.shadowColor = color.cgColor
view.layer.shadowOpacity = 1
view.layer.shadowOffset = offset
view.layer.shadowRadius = radius
return view
}
func addTwoShadowViews() {
// Create UIView.
let redShadowView = shadowView(color: .red, offset: CGSize(width: 0, height: -20))
let greenShadowView = shadowView(color: .green, offset: CGSize(width: 0, height: 20))
view.addSubview(redShadowView)
view.addSubview(greenShadowView)
NSLayoutConstraint.activate([
redShadowView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
redShadowView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
redShadowView.widthAnchor.constraint(equalToConstant: 100),
redShadowView.heightAnchor.constraint(equalToConstant: 100),
greenShadowView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
greenShadowView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
greenShadowView.widthAnchor.constraint(equalToConstant: 100),
greenShadowView.heightAnchor.constraint(equalToConstant: 100)
])
}
}
Это дает:
Не беспокойся. Мы все были там. ржу не могу.
Я еще плохо знаю правила. Спасибо за пояснение.