컬렉션 뷰셀의 Image Overlay를 tvOS10에서도 실현한다

15612 단어 tvOSUIKitSwift

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

좋은 웹페이지 즐겨찾기