컬렉션 뷰셀의 Image Overlay를 tvOS10에서도 실현한다
Image Overlay란?
tvOS11에서 등장한 UIImageView에 UIView를 겹쳐 Parallax 애니메이션시킬 수 있는 API입니다. var overlayContentView: UIView
에 addSubview 하는 형태가 됩니다.
이 예에서는 Free
의 라벨이 포커스시에 밖으로 튀어나와 애니메이션하고 있습니다.
Parallax 효과는 tvOS10까지는 UICollectionViewCell이 아니라 UIImageView의 Image뿐이므로 만약 이미지 위에 무언가 오버레이하고 싶다면 tvOS10까지는 전부 이미지로 할 필요가 있습니다.
동적인 데이터의 경우 억지로 생각할지도 모릅니다만, 고리와 해 보면 의외로 잘 되었습니다. AbemaTV에서는 조금 전부터 이 구현이 들어 있었습니다만, 이 기회에 OSS화했습니다.
toshi0383/ImageOverlay
이것을 사용하면, tvOS9, 10에서도 간단하게 Image Overlay 같은 UI를 실현할 수 있습니다.
tvOS9,10에서는 Free
의 라벨은 이미지로 렌더링되므로 이미지에서 벗어나지 않고 함께 확대, 애니메이션이 되어 있는 것을 알 수 있다고 생각합니다.
전화는 이런 느낌이 듭니다.
import ImageOverlay
import UIKit
final class CollectionViewCell: UICollectionViewCell {
@IBOutlet private weak var imageView: UIImageView!
...
override func prepareForReuse() {
super.prepareForReuse()
imageView.io.clearOverlays()
}
func configure() {
let image = UIImage(named: "High Sierra")!
let overlays: [OverlayProtocol] = [ViewAsOverlay()]
imageView.io.addOverlays(with: image, overlays: overlays)
}
OverlayViewProtocol
OverlayViewProtocol에서 UIView를 반환하면 UIView -> [CALayer] => UIImage로 변환됩니다. 오토 레이아웃에도 대응하고 있으므로, 언제나 그대로 View 계층을 짜 가면 문제 없습니다. xib에서 초기화하는 것도 물론 좋습니다.
import ImageOverlay
struct ViewAsOverlay: OverlayViewProtocol {
var view: UIView {
let frame = CGRect(x: 0, y: 0, width: 400, height: 225)
let v = UIView(frame: frame)
v.backgroundColor = .red
v.alpha = 0.3
let child = UIView()
child.alpha = 1.0
child.backgroundColor = .blue
child.translatesAutoresizingMaskIntoConstraints = false
v.addSubview(child)
NSLayoutConstraint.activate([
child.centerXAnchor.constraint(equalTo: v.centerXAnchor),
child.centerYAnchor.constraint(equalTo: v.centerYAnchor),
child.widthAnchor.constraint(equalToConstant: 100),
child.heightAnchor.constraint(equalToConstant: 100),
])
return v
}
}
OverlayProtocol
세세하게 설정을 한 CALayer를 직접 반환하고 싶은 경우는 OverlayProtocol을 이용합니다.
public struct TextOverlay: OverlayProtocol {
public let layers: [CALayer]
public init(text: String, font: UIFont, foregroundColor: UIColor = .white, size: CGSize, textOrigin: CGPoint) {
let textLayer = _textLayer(text: text, font: font, foregroundColor: foregroundColor, origin: textOrigin, size: size, scale: Scale.value)
self.layers = [textLayer]
}
}
private func _textLayer(text: String, font: UIFont, foregroundColor: UIColor, origin: CGPoint, size: CGSize, scale: CGFloat) -> CALayer {
let textSize = NSString(string: text).size(withAttributes: [NSAttributedStringKey.font: font])
let scaledTextSize = textSize.scaled(scale)
let scaledOrigin = origin.scaled(scale)
let textLayer = CATextLayer()
textLayer.string = text
textLayer.font = font
textLayer.fontSize = font.pointSize * scale
textLayer.foregroundColor = foregroundColor.cgColor
textLayer.frame = CGRect(origin: .zero, size: scaledTextSize)
textLayer.alignmentMode = kCAAlignmentCenter
textLayer.contentsScale = UIScreen.main.scale
let _layer = CALayer()
_layer.bounds = CGRect(origin: scaledOrigin, size: size.scaled(scale))
_layer.backgroundColor = UIColor.clear.cgColor
_layer.contentsScale = UIScreen.main.scale
_layer.addSublayer(textLayer)
return _layer
}
FillAspectRatioOverlay.swift
내장에서 FillAspectRatioOverlay라는 Overlay를 제공합니다.
tvOS11이라면 이런 해킹 필요 없다고?
그렇게 생각했던 무렵이 나에게도있었습니다.
이번에 실제로 만들어 보았습니다. tvOS11이라서 뭐든지 overlayContentView
를 사용하면 좋다는 것은 아닙니다. 예를 들어 위에서 소개한 여백 검정 채우기 Overlay입니다만, 이것을 UIImage가 아니라 CALayer로서 overlayContentView
에 표시하면, 포커스시에 Parallax 모션 해 버리므로, 여백이 어긋나 버립니다.
요약
Image Overlay 관련 해킹을 소개했습니다.
이 라이브러리를 사용하면 간단하게 오버레이의 이미지 렌더링과 Image Overlay의 양도를 실현할 수 있어 편리합니다. 오라에게 스타를 나눠줘 🤤
htps : // 기주 b. 코 m / 토시 0383 / 이마게 오오 ぇ r y
Reference
이 문제에 관하여(컬렉션 뷰셀의 Image Overlay를 tvOS10에서도 실현한다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/toshi0383/items/25656591674b88adbc48
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
이것을 사용하면, tvOS9, 10에서도 간단하게 Image Overlay 같은 UI를 실현할 수 있습니다.
tvOS9,10에서는
Free
의 라벨은 이미지로 렌더링되므로 이미지에서 벗어나지 않고 함께 확대, 애니메이션이 되어 있는 것을 알 수 있다고 생각합니다.전화는 이런 느낌이 듭니다.
import ImageOverlay
import UIKit
final class CollectionViewCell: UICollectionViewCell {
@IBOutlet private weak var imageView: UIImageView!
...
override func prepareForReuse() {
super.prepareForReuse()
imageView.io.clearOverlays()
}
func configure() {
let image = UIImage(named: "High Sierra")!
let overlays: [OverlayProtocol] = [ViewAsOverlay()]
imageView.io.addOverlays(with: image, overlays: overlays)
}
OverlayViewProtocol
OverlayViewProtocol에서 UIView를 반환하면 UIView -> [CALayer] => UIImage로 변환됩니다. 오토 레이아웃에도 대응하고 있으므로, 언제나 그대로 View 계층을 짜 가면 문제 없습니다. xib에서 초기화하는 것도 물론 좋습니다.
import ImageOverlay
struct ViewAsOverlay: OverlayViewProtocol {
var view: UIView {
let frame = CGRect(x: 0, y: 0, width: 400, height: 225)
let v = UIView(frame: frame)
v.backgroundColor = .red
v.alpha = 0.3
let child = UIView()
child.alpha = 1.0
child.backgroundColor = .blue
child.translatesAutoresizingMaskIntoConstraints = false
v.addSubview(child)
NSLayoutConstraint.activate([
child.centerXAnchor.constraint(equalTo: v.centerXAnchor),
child.centerYAnchor.constraint(equalTo: v.centerYAnchor),
child.widthAnchor.constraint(equalToConstant: 100),
child.heightAnchor.constraint(equalToConstant: 100),
])
return v
}
}
OverlayProtocol
세세하게 설정을 한 CALayer를 직접 반환하고 싶은 경우는 OverlayProtocol을 이용합니다.
public struct TextOverlay: OverlayProtocol {
public let layers: [CALayer]
public init(text: String, font: UIFont, foregroundColor: UIColor = .white, size: CGSize, textOrigin: CGPoint) {
let textLayer = _textLayer(text: text, font: font, foregroundColor: foregroundColor, origin: textOrigin, size: size, scale: Scale.value)
self.layers = [textLayer]
}
}
private func _textLayer(text: String, font: UIFont, foregroundColor: UIColor, origin: CGPoint, size: CGSize, scale: CGFloat) -> CALayer {
let textSize = NSString(string: text).size(withAttributes: [NSAttributedStringKey.font: font])
let scaledTextSize = textSize.scaled(scale)
let scaledOrigin = origin.scaled(scale)
let textLayer = CATextLayer()
textLayer.string = text
textLayer.font = font
textLayer.fontSize = font.pointSize * scale
textLayer.foregroundColor = foregroundColor.cgColor
textLayer.frame = CGRect(origin: .zero, size: scaledTextSize)
textLayer.alignmentMode = kCAAlignmentCenter
textLayer.contentsScale = UIScreen.main.scale
let _layer = CALayer()
_layer.bounds = CGRect(origin: scaledOrigin, size: size.scaled(scale))
_layer.backgroundColor = UIColor.clear.cgColor
_layer.contentsScale = UIScreen.main.scale
_layer.addSublayer(textLayer)
return _layer
}
FillAspectRatioOverlay.swift
내장에서 FillAspectRatioOverlay라는 Overlay를 제공합니다.
tvOS11이라면 이런 해킹 필요 없다고?
그렇게 생각했던 무렵이 나에게도있었습니다.
이번에 실제로 만들어 보았습니다. tvOS11이라서 뭐든지 overlayContentView
를 사용하면 좋다는 것은 아닙니다. 예를 들어 위에서 소개한 여백 검정 채우기 Overlay입니다만, 이것을 UIImage가 아니라 CALayer로서 overlayContentView
에 표시하면, 포커스시에 Parallax 모션 해 버리므로, 여백이 어긋나 버립니다.
요약
Image Overlay 관련 해킹을 소개했습니다.
이 라이브러리를 사용하면 간단하게 오버레이의 이미지 렌더링과 Image Overlay의 양도를 실현할 수 있어 편리합니다. 오라에게 스타를 나눠줘 🤤
htps : // 기주 b. 코 m / 토시 0383 / 이마게 오오 ぇ r y
Reference
이 문제에 관하여(컬렉션 뷰셀의 Image Overlay를 tvOS10에서도 실현한다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/toshi0383/items/25656591674b88adbc48
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Image Overlay 관련 해킹을 소개했습니다.
이 라이브러리를 사용하면 간단하게 오버레이의 이미지 렌더링과 Image Overlay의 양도를 실현할 수 있어 편리합니다. 오라에게 스타를 나눠줘 🤤
htps : // 기주 b. 코 m / 토시 0383 / 이마게 오오 ぇ r y
Reference
이 문제에 관하여(컬렉션 뷰셀의 Image Overlay를 tvOS10에서도 실현한다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/toshi0383/items/25656591674b88adbc48텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)