버튼이나 카드 뷰에 그림자가 들어가면 화면이 더 입체적이고 깊이감 있게 보인다.
이번에 디자인 시안에 그림자가 포함되어 있어서 직접 구현하게 되었고,
단순히 뷰에 속성을 추가하는 것 같아 보여도 실제로는 Core Animation에서 별도의 과정이 필요하다는 걸 알 수 있었다.
구현 과정
UIKit에서 뷰에 그림자를 주려면 UIView 자체가 아니라 그 뷰의 layer에 접근해야 한다.
대표적으로 사용하는 속성은 다음과 같다.
someView.layer.shadowColor = UIColor.black.cgColor
someView.layer.shadowOpacity = Float(0)
someView.layer.shadowOffset = CGSize(width: 1, height: -3)
someView.layer.shadowRadius = CGFloat(3)
someView.layer.masksToBounds = false
주요 속성 설명
- shadowColor: CGColor? = 그림자의 색상 - default: black
- shadowOpacity: Float = 그림자의 투명도 (0 ~ 1) - default: 0.0
- shadowOffset: CGSize = 그림자가 어디로 퍼질지 (x, y 좌표) - default: 0.0, -3.0
- shadowRadius: CGFloat = 그림자의 블러 정도: default: 3.0
- masksToBounds: 혹은 clipsToBounds를 false로 설정해야 그림자가 잘리지 않음
성능 최적화: shadowPath
하지만 shadow 속성만 주면 시스템이 매번 그림자 모양을 동적으로 계산해야 한다.
특히 뷰가 복잡하거나 스크롤되는 상황에서는 성능에 부담이 된다.
이럴 때는 shadowPath를 지정해주면 GPU가 불필요한 계산을 하지 않아도 된다.
override func layoutSubviews() {
super.layoutSubviews()
someView.layer.shadowPath = UIBezierPath(
roundedRect: someView.bounds,
cornerRadius: someView.layer.cornerRadius
).cgPath
}
- shadowPath: CGPath? = 그림자의 모양 - defualt: nil
- shadowPath를 명시하면 Core Animation이 “그림자 모양이 이미 정해져 있으니 그대로 쓰면 된다”라고 판단
→ 퍼포먼스 개선 - 특히 cornerRadius가 적용된 뷰라면 roundedRect로 설정해주는 게 깔끔하다.
기존 속성들로는 구현하기 어려운 모양을 shadowPath를 이용해서 구현 가능하다고 한다.
Swift Shadow(그림자) 설정 알아보기
안녕하세요. 오늘은 간만에 간단하면서도 은근 자주 쓰이는 그림자 기능에 대해 이야기 해볼까합니다. 그림자 효과가 어떤 건지 궁금하신 분들을 위해 맛보기를 보여드리면 아래같은거 말하는
world-of-larooly.tistory.com
배운 점
- cornerRadius와 그림자 충돌
clipsToBounds 또는 masksToBounds를 true로 설정하면 그림자가 안 보인다.
그림자까지 보이게 하려면 꼭 false로 둬야 한다. - 퍼포먼스 고려
그림자는 Core Animation에서 오프스크린 렌더링을 발생시킨다.
즉, GPU가 별도의 버퍼에 그림자를 그린 뒤 원래 뷰와 합성하는 과정을 거쳐야 하므로 성능 비용이 든다.
그림자를 남발하면 스크롤 시 프레임 드랍이 생길 수 있으니, 버튼이나 카드 뷰 같은 핵심 요소에만 적절히 적용하는 게 좋다. - shadowPath로 최적화 가능
뷰의 형태가 고정돼 있거나 단순하다면 shadowPath를 지정해주는 게 성능상 안전하다.
참고
Swift Shadow(그림자) 설정 알아보기
안녕하세요. 오늘은 간만에 간단하면서도 은근 자주 쓰이는 그림자 기능에 대해 이야기 해볼까합니다. 그림자 효과가 어떤 건지 궁금하신 분들을 위해 맛보기를 보여드리면 아래같은거 말하는
world-of-larooly.tistory.com