フェードイン・フェードアウト処理は、アプリ開発していて頻出の処理だと思います。
ベタ書きでも普通に書けちゃう程度の簡単な処理なのでそうしている人が多い気がしますが、メソッド用意しておくと地味にかなり便利です。
enum FadeType: NSTimeInterval {
case
Normal = 0.2,
Slow = 1.0
}
extension UIView {
func fadeIn(type: FadeType = .Normal, completed: (() -> ())? = nil) {
fadeIn(duration: type.rawValue, completed: completed)
}
/** For typical purpose, use "public func fadeIn(type: FadeType = .Normal, completed: (() -> ())? = nil)" instead of this */
func fadeIn(duration: NSTimeInterval = FadeType.Slow.rawValue, completed: (() -> ())? = nil) {
alpha = 0
hidden = false
UIView.animateWithDuration(duration,
animations: {
self.alpha = 1
}) { finished in
completed?()
}
}
func fadeOut(type: FadeType = .Normal, completed: (() -> ())? = nil) {
fadeOut(duration: type.rawValue, completed: completed)
}
/** For typical purpose, use "public func fadeOut(type: FadeType = .Normal, completed: (() -> ())? = nil)" instead of this */
func fadeOut(duration: NSTimeInterval = FadeType.Slow.rawValue, completed: (() -> ())? = nil) {
UIView.animateWithDuration(duration
, animations: {
self.alpha = 0
}) { [weak self] finished in
self?.hidden = true
self?.alpha = 1
completed?()
}
}
}
メリット
ベタに書いていると「本当はふわっと表示させた方がベターかもだけど、面倒だからパリッと表示させちゃうこと」などもあり得ると思いますが、簡単に呼べるようにしているとそういう手抜き心を防ぎやすいです( ´・‿・`)
特に、alpha: 0
の時に丁寧にhidden: true
にするのが地味に面倒に感じてました(´-ω-`)
また、 アニメーションのdurationに統一感が生まれます。 さらに、後から統一的に値を変更するのも容易です。
上の例の場合、あっさりしたところは0.2秒、じわっと切り替えたいところは1秒、と基本2通りで、どうしてもそれ以外使いたい時はduration直接指定も可能、という作りになってます。
ベタ書きだと、この管理がわりと適当になっちゃったりしがちです。特にチーム開発だと。
呼び出し
単純な呼び出し
let view = UIView()
// これだけでふわっとフェードイン
view.fadeIn(type: .Slow)
// 完了タイミングで何かしたい場合はクロージャーも記述
view.fadeIn(type: .Slow) { [weak self] in
self?.someMethod()
}
SDWebImageと組み合わせた例
【追記】Kingfisherで次のように書くのがオススメです
imageView.kf.setImage(with: url,
placeholder: placeholder,
options: [.transition(ImageTransition.fade(1))])
-
placeholder
引数は省略しても良いですが、適当な空画像を指定すると、よりキレイです - SDWebImageでも同様に簡単な方法があったかもしれないですが調べていません
--- 以下原文です ---
こんな感じにSDWebImageを使った処理を定義しておくと、キャッシュ済みの時は即時表示で、ダウンロードしてきた時はふわっとフェードイン表示という処理を1行で呼び出せます。
extension UIImageView {
func setImageSmoothly(url: NSURL, placeholderImage: UIImage?) {
sd_setImageWithURL(url, placeholderImage: placeholderImage) { [weak self] image, error, cacheType, imageUrl in
if error != nil {
return
}
if image != nil && cacheType == .None {
self?.fadeIn(type: FadeType.Slow)
}
}
}
}
// これだけで画像をダウンロードしつつふわっとフェードイン表示できる
imageView.setImageSmoothly(url, placeholderImage: nil)
こういう共通処理はどこに書いてる?
ライブラリとして切り出すか迷うところですが、要件に合わせてオプション引数とか追加したくなるし、このあたりは自分のソースとして書いちゃった方が取り回し良く感じちゃいます。
実際、ここに載せたのも、実際のコードはもう少し複雑になってます。
Embedded Frameworkを利用
僕はこれ系はEmbedded Frameworkに定義しちゃってます。
命名は迷いつつ、UIView+Lib.swift
としてます。
Embedded Frameworkにする場合、呼び出し可能にするために、enumとメソッドにpublic
指定が必要です。
final
も付けるとベターです。
参考: Swiftのfinal・private・Whole Module Optimizationを理解しDynamic Dispatchを減らして、パフォーマンスを向上する - Qiita
メソッド名は、衝突防ぐようにプレフィックス付けた方が良いなど言われていますが、僕はライブラリとして公開とかするのでは無ければ、無くて良いかなと思っています。
Embedded Frameworkにすると名前空間分かれる言っても、特に既存クラスの拡張メソッドの場合はそれ関係無く衝突は避けられないのでやや不確実ではありますが。(import
をカットすれば一応避けられるものの)