IOS 7の全体的な感じとして、ぼかし効果を画面の特定の部分に適用してそれを難読化しますが、ぼかしをすぐに投げるだけではなく、それをアニメーション化してからアニメーション化したいので、ユーザーには、ぼかし効果が適用されているのがほとんど見えます。
まるでPhotoshopのように、ガウスぼかしの値を1度に0から10ではなく0から10に少しずつ変更しました。
私はこれに対していくつかの解決策を試しましたが、最も一般的な提案は、ぼかしのないビューの上にぼかしビューを単に配置してから、ぼかしビューのアルファ値を下げることです。
これは機能します大丈夫が、遷移がないため、あまりオーバーレイではありません。例:
そのような効果を達成するためのより良い方法は何でしょうか?私は GPUImage に精通していますが、それでそれを達成する方法はわかりません。
また、ぼかしのパーセンテージを制御できるので、ユーザーからインタラクティブに適用できると便利です。 (例:ユーザーが途中までドラッグした、ブラーが半分適用された、など)
IOS 9以降では、視覚効果ビューの効果をアニメーション化できます。
[UIView animateWithDuration:0.3 animations: ^ {
visualEffectView.effect = blurEffect;
} completion:nil];
これにより、ぼかし半径をアニメートするという期待される効果が得られます。
ぼやけていないビュー->ぼやけているビューからクロスフェードをアニメートすると、十分に楽しいと思います。ぼかしていないビューの上にあるぼかしビューの表示をアニメーション化する必要があります。
blurView
がぼかし効果を含むビューであると仮定しましょう。
アニメーション化された遷移を達成する方法の2つの例を次に示します。
[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
[self.view addSubview:blurView];
} completion:nil];
ここでは、blurView
がすでに設定されていると想定し、アニメーションのサブビューとして追加を移行します。
別の方法でこれを実現することもできます。
blurView.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations: ^ {
blurView.alpha = 1.0f;
} completion:nil];
ここでは、ぼかしビューを透明にして、その外観をアニメーション化します。このメソッドを使用してもhidden
では機能しないため、alpha
プロパティを使用する必要があることに注意してください。
インタラクティブにぼかしの量を制御したい場合は、次の例をご覧ください。
まず、ぼかしたいビューの画像を作成します。
UIGraphicsBeginImageContextWithOptions(nonBlurredView.bounds.size, NO, self.view.window.screen.scale);
[nonBlurredView drawViewHierarchyInRect:nonBlurredView.bounds afterScreenUpdates:NO];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
この画像を保管してください。ビューが変更された場合にのみ、同様の方法で再描画します。それ以外の場合は、階層の描画にコストがかかるため、この画像を再利用する必要があります。
ここで、ぼかす必要がある場合は、次のコードを使用します。
CIImage *imageToBlur = [CIImage imageWithCGImage:snapshotImage.CGImage];
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
[gaussianBlurFilter setValue:imageToBlur forKey: @"inputImage"];
[gaussianBlurFilter setValue:@10 forKey: @"inputRadius"]; //Here you input the blur radius - the larger, the
CIImage *resultImage = [gaussianBlurFilter valueForKey: @"outputImage"];
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];
inputRadius
入力は、実行されるブラーの量を設定します。これをアニメートすると、インタラクティブな感覚を実現できます。
ただし、前者の方法の方がはるかに簡単で、ユーザーにとっても気分が良いと思います。
これはOS Xでは簡単で、1つのビューがその背後のビューにエフェクトをCIFilterでき、プロセッサが強力で高速です。ただし、iOSではビュー合成フィルターがなく、ぼかしにはしばらく時間がかかります。アニメーションのフレームと同じくらい速く、ライブで繰り返し行うことはできません。したがって、何らかの形の妥協が必要です。
ただし、ぼかしたいことを事前に十分に理解している場合は、ぼかしのグラデーションを使用して一連の画像を準備できます(ぼかしなし、少しぼかし、少しぼかしなど)。次に、画像を組み立てて、アニメーション化されたUIImageViewの「フレーム」として「再生」します。
しかし、それは私が実際に助言することではありません。私がすることは、ぼかし画像とぼかしのない画像を準備し、CIDissolveTransitionを使用して、ぼかしのない画像からぼかし画像にディゾルブすることです。いいえ、ぼかしを徐々に適用するのと同じではありませんが、計算コストが低く、ツールボックスで最高の「ディゾルブ」エフェクトです。
私は、可変ぼかし半径とフレームレート( MSLiveBlur )でライブぼかしにGPUImageを使用する小さなプロジェクトを開発しました-これはまさに必要なもののように聞こえます。
サンプルアプリには、質問で述べたように、ユーザーアクションに応じてぼかしレベルを増減するスライダーがあります。ユーザーの操作なしでアニメーション化したい場合は、最終値に達するまでぼかし半径をゆっくりと増加させるタイマーを作成できます。ただし、このソリューションではCoreAnimationを使用できません。
[[MSLiveBlurView sharedInstance] setBlurInterval:0.2];
[[MSLiveBlurView sharedInstance] blurRect:someView.frame];
// Count x from 0 to your final radius
[MSLiveBlurView sharedInstance].blurRadius = x;
コーディングの問題に対する既製のソリューションを提案することはめったにありません。ただし、この場合は LiveFrost をお勧めします。これは、人気のあるiOS 7ガウスぼかし効果の複製にのみ焦点を当てた、本当に堅固なUIViewサブクラスです。
また、このクラスの設計に関する決定については、著者のブログを読むことをお勧めします。私はiOS 7のリリース以来、このトピックについて具体的に多くの研究を行ってきましたが、このコードについて文字通りゼロの苦情を抱えています。
そのままの状態でぼかしアニメーションも付いています!頑張って :)
これは、事前計算された画像でぼかしをアニメーション化するために使用できる関数です。あなたはGPUImageに精通していると言ったので、それを使用しました(ただし、単純なぼかしアルゴリズムでも動作します)。
これにより、CPUを1〜2%のコストでリアルブラーリアルタイムでアニメーション化できます。
// configuration
let imageCount: Int = 10
let blurMax: Float = 40.0
// keep images in memory
var currentIdx: Int = 0
var imgs: [UIImage] = []
// func that create the precomputed images with GPUImage (call it in the viewDidLoad for example)
func initBlur() {
let blur = GaussianBlur()
let myImage: UIImage = UIImage(named: "your_image")!
let pictureInput = PictureInput(image: myImage)
let pictureOutput = PictureOutput()
pictureOutput.onlyCaptureNextFrame = false
pictureOutput.imageAvailableCallback = { image in
self.imgs.append(image)
}
pictureInput --> blur --> pictureOutput
for i in 0...imageCount {
blur.blurRadiusInPixels = (Float(i) / Float(imageCount)) * blurMax
pictureInput.processImage(synchronously: true)
}
}
// function that return the correct image from the image set with a blur percentage from a value between 0 and 1 where 0 = no blur and 1 full blurred.
func getBlurredImage(value: Float) -> UIImage? {
// return nil if there isn't precompiled images
if imgs.count == 0 {
return nil
}
// get the desired blurred image index
let idx = Int(value * Float(imageCount - 1))
// if the index changed, check the correctness of the index
if currentIdx != idx {
if idx < 0 {
currentIdx = 0
}
else if idx >= imgs.count {
currentIdx = imageCount - 1
}
else {
currentIdx = idx
}
}
return imgs[currentIdx]
}
それだけです。次に、たとえばタイマーを使用したり、scrollViewDidScroll関数で使用したりできます。
imageView.image = getBlurredImage(value: yOffset / height)