3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

tvOSAdvent Calendar 2017

Day 13

コレクションビューセルのImage OverlayをtvOS10でも実現する

Last updated at Posted at 2017-12-12

Image Overlayとは

tvOS11で登場した、UIImageViewにUIViewを重ねてParallaxアニメーションさせることができるAPIです。var overlayContentView: UIViewにaddSubviewしていく形になります。
この例だと、Freeのラベルがフォーカス時に外にはみ出してアニメーションしています。
image

ParallaxエフェクトするのはtvOS10まではUICollectionViewCellではなくUIImageViewのImageのみだったので、もし画像の上に何かオーバーレイしたい場合、tvOS10までは 全部画像にする必要があります。
動的なデータの場合無理やんと思うかもしれませんが、ゴリっとやってみたら意外とうまくいきました。AbemaTVでは少し前からこの実装が入っていたのですが、この機会にOSS化しました。

toshi0383/ImageOverlay

これを使うと、tvOS9,10でも簡単にImage OverlayっぽいUIを実現できます。
tvOS9,10ではFreeのラベルは画像としてレンダリングされるので、画像からはみ出さず一緒に拡大、アニメーションされてるのがわかると思います。
image

呼び出しはこんな感じになります。

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の両刀遣いが実現できて便利です。オラにスターを分けてくれ🤤
https://github.com/toshi0383/ImageOverlay

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?