วิธีการทำให้ UIVisualEffectView และ / หรือ UIBlurEffect จางลงในและนอก


93

ฉันต้องการทำให้ UIVisualEffectsView จางลงด้วย UIBlurEffect เข้าและออก:

var blurEffectView = UIVisualEffectView()
blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))

ฉันใช้ภาพเคลื่อนไหวปกติภายในฟังก์ชั่นที่เรียกโดย a UIButtonเพื่อทำให้มันจางลงเช่นเดียวกับการเลือนหายไป แต่.alpha = 0& hidden = true:

blurEffectView.hidden = false
UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut) {
    self.blurEffectView.alpha = 1
}

ตอนนี้การซีดจางทั้งสองทิศทางใช้งานได้ แต่ทำให้ฉันมีข้อผิดพลาดเมื่อจางหายไป :

<UIVisualEffectView 0x7fdf5bcb6e80>จะถูกขอให้เคลื่อนไหวความทึบของมัน สิ่งนี้จะทำให้เอฟเฟกต์ดูเสียจนกว่าความทึบจะกลับมาเป็น 1

คำถาม

ฉันจะเลือนเข้าUIVisualEffectViewและออกได้อย่างไรโดยไม่ทำลายและมีการเปลี่ยนแปลงที่ซีดจาง

บันทึก

  • ฉันพยายามใส่UIVisualEffectViewลงไปUIViewและทำให้คนนั้นจางหายไป แต่ก็ไม่ประสบความสำเร็จ

คุณสามารถหลีกเลี่ยงข้อผิดพลาดได้โดย 1. ไม่กำหนดสไตล์เริ่มต้นให้กับเบลอเอฟเฟกต์ กล่าวคือ var เบลอEffectView = UIVisualEffectView () และจากนั้น 2. กำหนดค่าเบลอเอฟเฟกต์ให้กับเบลอเอฟเฟกต์วิวภายในบล็อกแอนิเมชั่น 3. การสร้างภาพเคลื่อนไหว "การกำหนดค่าเบลอเอฟเฟกต์ให้เป็นเบลอเอฟเฟกต์วิว" จะกระทำแทนการปรับแต่งเบลอเอฟเฟกต์วิวอัลฟา ** ข้อผิดพลาดนี้จะปรากฏขึ้นแม้ว่าคุณจะกำหนดค่าเริ่มต้นให้ไม่มีค่าใด ๆ จากนั้นเพิ่มกลับเข้าไป ดังนั้นกุญแจสำคัญในการป้องกันข้อผิดพลาดคืออย่ากำหนดเอฟเฟกต์ให้กับเบลอเอฟเฟกต์วิวจนกว่าจะบล็อกภาพเคลื่อนไหว
ObjectiveTC

นอกจากนี้ยังต้องพูดถึงเบลอเอฟเฟกต์วิวต้องมีอัลฟา = 1.0 เพื่อหลีกเลี่ยงข้อผิดพลาด การปลอมแปลงอัลฟ่าไม่ว่าด้วยวิธีใดก็ตามจะทำให้เกิดข้อผิดพลาด เช่นก่อนที่จะบล็อกแอนิเมชั่นคุณตั้งค่าเบลอเอฟเฟกต์วิว. อัลฟา = 0.7 จากนั้นในแอนิเมชั่นบล็อกที่คุณกำหนดเบลอเอฟเฟกต์วิวเอฟเฟกต์ = เบลอเอฟเฟกต์ข้อผิดพลาดจะเกิดขึ้น
ObjectiveTC

คำตอบ:


187

ฉันคิดว่านี่เป็นสิ่งใหม่ใน iOS9 แต่ตอนนี้คุณสามารถตั้งค่าเอฟเฟกต์ของUIVisualEffectViewบล็อกภาพเคลื่อนไหวได้แล้ว:

let overlay = UIVisualEffectView()
// Put it somewhere, give it a frame...
UIView.animate(withDuration: 0.5) {
    overlay.effect = UIBlurEffect(style: .light)
}

ตั้งค่าเป็นnilลบ

สำคัญมาก - เมื่อทดสอบสิ่งนี้บนเครื่องจำลองตรวจสอบให้แน่ใจว่าได้ตั้งค่าการแทนที่คุณภาพกราฟิกของเครื่องจำลองเป็นคุณภาพสูงเพื่อให้สามารถใช้งานได้


1
ทำงานได้อย่างสมบูรณ์ ขอบคุณ.
Baza207

เยี่ยมมาก! อย่างที่คุณบอกว่าใช้ไม่ได้กับ iOS 8 แม้ว่า: /
LinusGeffarth

เป็นเพราะสิ่งที่ฉันเขียนไว้ข้างต้น ฉันได้รับการอนุมัติแล้วอย่างไรก็ตาม @jpros
LinusGeffarth

10
คุณยังสามารถตั้งค่าเอฟเฟกต์เป็นศูนย์เพื่อให้ได้ "ภาพเบลอ" ที่สวยงาม
jpros

1
@jpros ช่วยอธิบายหน่อยได้ไหมว่า "เบลอออกมา" หมายความว่าอย่างไร
ndmeiri

19

เอกสารแอปเปิ้ล (ปัจจุบัน) กล่าว ...

เมื่อใช้คลาส UIVisualEffectView หลีกเลี่ยงค่าอัลฟาที่น้อยกว่า 1

และ

การตั้งค่าอัลฟ่าให้น้อยกว่า 1 ในมุมมองเอฟเฟกต์ภาพหรือซูเปอร์วิวใด ๆ ทำให้เอฟเฟกต์หลายอย่างดูไม่ถูกต้องหรือไม่แสดงเลย

ฉันเชื่อว่าบริบทสำคัญบางอย่างขาดหายไปที่นี่ ...

ฉันขอแนะนำว่าเจตนาคือการหลีกเลี่ยงค่าอัลฟาที่น้อยกว่า 1 สำหรับการดูแบบต่อเนื่อง ในความเห็นที่ต่ำต้อยของฉันสิ่งนี้ใช้ไม่ได้กับภาพเคลื่อนไหวของมุมมอง

ประเด็นของฉัน - ฉันขอแนะนำว่าค่าอัลฟาที่น้อยกว่า 1 เป็นที่ยอมรับสำหรับภาพเคลื่อนไหว

ข้อความเทอร์มินัลระบุ:

UIVisualEffectView จะถูกขอให้เคลื่อนไหวความทึบของมัน สิ่งนี้จะทำให้เอฟเฟกต์ดูเสียจนกว่าความทึบจะกลับมาเป็น 1

อ่านอย่างระมัดระวังผลจะดูเหมือนจะเสีย คะแนนของฉันเกี่ยวกับสิ่งนี้:

  • การหยุดพักที่ชัดเจนมีความสำคัญมากสำหรับมุมมองที่คงอยู่ - ไม่เปลี่ยนแปลง
  • UIVisualEffectมุมมองต่อเนื่อง / ไม่เปลี่ยนแปลงที่มีค่าอัลฟาน้อยกว่า 1 จะไม่แสดงตามที่ตั้งใจ / ออกแบบโดย Apple และ
  • ข้อความในเทอร์มินัลไม่ใช่ข้อผิดพลาดเพียงแค่คำเตือน

เพื่อขยายคำตอบของ @ jrturton ด้านบนที่ช่วยฉันแก้ปัญหาฉันจะเพิ่ม ...

หากต้องการลบให้UIVisualEffectใช้รหัส (Objective-C) ต่อไปนี้:

UIView.animateWithDuration(1.0, animations: {
//  EITHER...
    self.blurEffectView.effect = UIBlurEffect(nil)
//  OR...
    self.blurEffectView.alpha = 0
}, completion: { (finished: Bool) -> Void in
    self.blurEffectView.removeFromSuperview()
} )

ผมประสบความสำเร็จในการใช้วิธีการทั้งสอง: การตั้งค่าeffectคุณสมบัติการnilและการตั้งค่าคุณสมบัติการalpha0

โปรดทราบว่าการตั้งค่าeffectให้nilสร้าง "แฟลชที่ดี" (เพื่อต้องการคำอธิบายที่ดีกว่า) ในตอนท้ายของภาพเคลื่อนไหวในขณะที่ตั้งค่าalphaให้0สร้างการเปลี่ยนแปลงที่ราบรื่น

(แจ้งให้เราทราบข้อผิดพลาดทางไวยากรณ์ ... ฉันเขียนใน obj-c)


ขอบคุณสำหรับการสนับสนุนของคุณ ฉันเข้าใจประเด็นของคุณ ข้อผิดพลาดได้รับการแก้ไขสำหรับฉันแล้วกับสิ่งที่คุณพูดถึง :)
LinusGeffarth

15

นี่คือวิธีแก้ปัญหาที่ฉันลงเอยซึ่งใช้ได้กับทั้ง iOS10 และเวอร์ชันก่อนหน้าโดยใช้ Swift 3

extension UIVisualEffectView {

    func fadeInEffect(_ style:UIBlurEffectStyle = .light, withDuration duration: TimeInterval = 1.0) {
        if #available(iOS 10.0, *) {
            let animator = UIViewPropertyAnimator(duration: duration, curve: .easeIn) {
                self.effect = UIBlurEffect(style: style)
            }

            animator.startAnimation()
        }else {
            // Fallback on earlier versions
            UIView.animate(withDuration: duration) {
                self.effect = UIBlurEffect(style: style)
            }
        }
    }

    func fadeOutEffect(withDuration duration: TimeInterval = 1.0) {
        if #available(iOS 10.0, *) {
            let animator = UIViewPropertyAnimator(duration: duration, curve: .linear) {
                self.effect = nil
            }

            animator.startAnimation()
            animator.fractionComplete = 1
        }else {
            // Fallback on earlier versions
            UIView.animate(withDuration: duration) {
                self.effect = nil
            }
        }
    }

}

คุณยังสามารถตรวจสอบส่วนสำคัญนี้เพื่อค้นหาตัวอย่างการใช้งาน


การใช้สิ่งUIViewPropertyAnimatorนี้เป็นสิ่งเดียวที่ดูเหมือนจะใช้ได้ใน iOS 11 ขอบคุณสำหรับสิ่งนี้!
LinusGeffarth

อย่าลืมเพิ่ม: import UIKit
Oleksandr

8

เพียงวิธีแก้ปัญหา - ใส่UIVisualEffectViewลงในมุมมองคอนเทนเนอร์และเปลี่ยนalphaคุณสมบัติสำหรับคอนเทนเนอร์นั้น วิธีนี้ใช้ได้ดีกับฉันใน iOS 9 ดูเหมือนว่าจะใช้ไม่ได้ใน iOS 10 อีกต่อไป


เย็น. ขอบคุณจะพยายาม :)
LinusGeffarth

1
คุณสามารถให้รหัสตัวอย่าง ดูเหมือนจะไม่ได้ผล
cnotethegr8

ใช้ได้กับฉันใน iOS 9
5hrp

@DerrickHunt เหมือนกันที่นี่. คุณพบวิธีแก้ปัญหาหรือไม่?
damirstuhec

2
@damirstuhec หากโปรเจ็กต์ของคุณเป็น iOS 10 เท่านั้นคุณสามารถใช้คลาส UIViewPropertyAnimator ใหม่เพื่อทำให้ความแรงของ UIBlurView เคลื่อนไหวได้ หากคุณต้องการรองรับเวอร์ชันเก่าคุณสามารถใช้โค้ดด้านบนและใช้คีย์เวิร์ด #available เพื่อใช้ UIViewPropertyAnimator สำหรับอุปกรณ์ที่รัน 10 หวังว่านี่จะช่วยได้!
Derrick Hunt

5

คุณสามารถเปลี่ยนอัลฟาของมุมมองเอฟเฟ็กต์ภาพได้โดยไม่มีปัญหานอกเหนือจากคำเตือนในคอนโซล มุมมองอาจปรากฏเป็นโปร่งใสเพียงบางส่วนแทนที่จะเบลอ แต่โดยปกติแล้วจะไม่มีปัญหาหากคุณเพิ่งเปลี่ยนอัลฟ่าระหว่างการเคลื่อนไหว

แอปของคุณจะไม่ขัดข้องหรือถูกปฏิเสธสำหรับสิ่งนี้ ทดสอบบนอุปกรณ์จริง (หรือแปด) หากคุณพอใจกับรูปลักษณ์และประสิทธิภาพก็ใช้ได้ Apple แค่เตือนคุณว่าอาจดูหรือทำงานได้ไม่ดีเท่ากับมุมมองเอฟเฟกต์ภาพที่มีค่าอัลฟาเท่ากับ 1


5

คุณสามารถถ่ายภาพสแนปชอตของมุมมองพื้นฐานแบบคงที่และทำให้ภาพเข้าและออกจางลงโดยไม่ต้องสัมผัสความทึบของมุมมองเบลอ สมมติว่าไอวาร์เบลอ

func addBlur() {
    guard let blurEffectView = blurEffectView else { return }

    //snapShot = UIScreen.mainScreen().snapshotViewAfterScreenUpdates(false)
    let snapShot = self.view.snapshotViewAfterScreenUpdates(false)
    view.addSubview(blurEffectView)
    view.addSubview(snapShot)

    UIView.animateWithDuration(0.25, animations: {
        snapShot.alpha = 0.0
    }, completion: { (finished: Bool) -> Void in
        snapShot.removeFromSuperview()
    } )
}

func removeBlur() {
    guard let blurEffectView = blurEffectView else { return }

    let snapShot = self.view.snapshotViewAfterScreenUpdates(false)
    snapShot.alpha = 0.0
    view.addSubview(snapShot)

    UIView.animateWithDuration(0.25, animations: {
        snapShot.alpha = 1.0
    }, completion: { (finished: Bool) -> Void in
        blurEffectView.removeFromSuperview()
        snapShot.removeFromSuperview()
    } )
}

เป็นความคิดที่ดีเช่นกัน แต่ใช้ไม่ได้ผลกับเนื้อหาที่ไม่คงที่ (เคลื่อนไหว / ภาพเคลื่อนไหว) ภายใต้มุมมองเบลอ
LinusGeffarth

@LinusG. Apple บอกว่าไม่ควรเล่นกับอัลฟ่าที่เบลอ คุณสามารถใช้ CADisplayLink เพื่อจับภาพหน้าจอของมุมมองพื้นฐานของคุณจากนั้นแสดงภาพในมุมมองภาพ (อาจเป็นภาพที่คุณทำ - น้ำหนักเบาจริง) - และแสดงภาพเหล่านั้นในมุมมองด้านบนในขณะที่เปลี่ยนความทึบเป็น 0 เป็นไปได้ แต่มีมาก งาน.
David H

1
นี่เป็นวิธีเดียว (จนถึงตอนนี้) ฉันสามารถบรรลุสิ่งที่ฉันต้องการใน iOS 10 - จางหายไปในรูปแบบเต็มหน้าจอพร้อมเอฟเฟกต์เบลอที่มืด ขอบคุณ!
Graham

3

หากคุณต้องการจางหายไปในตัวคุณ UIVisualEffectView - สำหรับ ios10 ให้ใช้ UIViewPropertyAnimator

    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:nil];
    blurEffectView.frame = self.view.frame;
    blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    UIView *blackUIView = [[UIView alloc]initWithFrame:self.view.frame];
    [bacgroundImageView addSubview:blackUIView];
    [blackUIView addSubview:blurEffectView];
    UIViewPropertyAnimator *animator  = [[UIViewPropertyAnimator alloc] initWithDuration:4.f curve:UIViewAnimationCurveLinear animations:^{
        [blurEffectView setEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
    }];

จากนั้นคุณสามารถกำหนดเปอร์เซ็นต์ได้

[animator setFractionComplete:percent];

สำหรับ ios9 คุณสามารถใช้องค์ประกอบอัลฟา


2
คำถามนี้ติดแท็กโดยเฉพาะ "รวดเร็ว" ไม่ใช่ "วัตถุประสงค์ -c": โปรดระบุคำตอบใน Swift ขอบคุณ!
Eric Aya

1
ขอบคุณสำหรับ Objective C Code ฉันพบว่ามีประโยชน์เนื่องจากไม่มีตัวอย่างอื่น ๆ ในรายการ
Adam Ware

2

อัลฟาของ UIVisualEffectView จะต้องเป็น 1 เสมอฉันคิดว่าคุณสามารถบรรลุผลได้โดยการตั้งค่าอัลฟาของสีพื้นหลัง

ที่มา: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html


ปีเตอร์ช่วยอธิบายวิธีตั้งค่าสีพื้นหลังอัลฟ่าได้ไหม
บอริสย

@borisy ใช้colorWithAlphaComponent:วิธีการบนUIColorอินสแตนซ์ ไม่แน่ใจว่าจะได้เอฟเฟกต์เดียวกันกับการตั้งค่าสีพื้นหลังอย่างไร
ซวย

การเปลี่ยนองค์ประกอบอัลฟ่าพื้นหลังไม่ทำงานตามที่คาดไว้
Honghao Zhang

1

ฉันสร้าง uiview ซึ่งอัลฟ่าเป็น 0 และเพิ่มเบลอวิวเป็นมุมมองย่อยของสิ่งนั้น ดังนั้นฉันสามารถซ่อน / แสดงหรือปัดเศษมุมด้วยภาพเคลื่อนไหว


1

ฉันลงเอยด้วยวิธีแก้ปัญหาต่อไปนี้โดยใช้ภาพเคลื่อนไหวแยกกันสำหรับ UIVisualEffectViewและเนื้อหา ฉันใช้viewWithTag()วิธีนี้เพื่อรับการอ้างอิงถึงUIViewภายในไฟล์UIVisualEffectView.

let blurEffectView = UIVisualEffectView()
// Fade in
UIView.animateWithDuration(1) { self.blurEffectView.effect = UIBlurEffect(style: .Light) }    
UIView.animateWithDuration(1) { self.blurEffectView.viewWithTag(1)?.alpha = 1 }
// Fade out
UIView.animateWithDuration(1) { self.blurEffectView.effect = nil }    
UIView.animateWithDuration(1) { self.blurEffectView.viewWithTag(1)?.alpha = 0 }

ฉันต้องการให้แอนิเมชั่นเดี่ยวเปลี่ยนอัลฟ่ามากกว่า แต่วิธีนี้จะหลีกเลี่ยงข้อผิดพลาดและดูเหมือนว่าจะทำงานได้ดีเช่นกัน


1

ฉันเพิ่งมีปัญหานี้และวิธีที่ฉันได้รับคือการจัดวาง UIVisualEffectsView ใน UIView และทำให้อัลฟ่าของ UIView เคลื่อนไหว

สิ่งนี้ใช้ได้ดียกเว้นว่าทันทีที่อัลฟ่าเปลี่ยนไปต่ำกว่า 1.0 มันจะกลายเป็นสีขาวทึบและดูสั่นมาก ในการแก้ไขปัญหานี้คุณต้องตั้งค่าคุณสมบัติเลเยอร์ของ UIView ซึ่งcontainerView.layer.allowsGroupOpacity = falseจะป้องกันไม่ให้กระพริบเป็นสีขาว

ตอนนี้คุณสามารถเคลื่อนไหวใน / เลือน UIView ที่มีมุมมองเอฟเฟกต์ภาพและมุมมองย่อยอื่น ๆ โดยใช้คุณสมบัติอัลฟาและไม่ต้องกังวลกับความผิดพลาดของกราฟิกใด ๆ หรือการบันทึกข้อความเตือน


0
_visualEffectView.contentView.alpha = 0;

ในการเปลี่ยนอัลฟาของ UIVisualEffectView คุณควรเปลี่ยน contentView ของ _visualEffectView หากคุณเปลี่ยนอัลฟาของ _visualEffectView คุณจะได้รับสิ่งนี้

<UIVisualEffectView 0x7ff7bb54b490> is being asked to animate its opacity. This will cause the effect to appear broken until opacity returns to 1.

0

โดยปกติแล้วฉันต้องการทำให้ภาพเบลอเคลื่อนไหวเมื่อฉันกำลังนำเสนอตัวควบคุมมุมมองผ่านหน้าจอและต้องการเบลอตัวควบคุมมุมมองการนำเสนอ นี่คือส่วนขยายที่เพิ่มความเบลอ () และ unblur () ให้กับตัวควบคุมมุมมองเพื่ออำนวยความสะดวก:

extension UIViewController {

   func blur() {
       //   Blur out the current view
       let blurView = UIVisualEffectView(frame: self.view.frame)
       self.view.addSubview(blurView)
       UIView.animate(withDuration:0.25) {
           blurView.effect = UIBlurEffect(style: .light)
       }
   }

   func unblur() {
       for childView in view.subviews {
           guard let effectView = childView as? UIVisualEffectView else { continue }
           UIView.animate(withDuration: 0.25, animations: {
                effectView.effect = nil
           }) {
               didFinish in
               effectView.removeFromSuperview()
           }
       }
   }
}

แน่นอนคุณสามารถทำให้สิ่งนี้มีประสิทธิภาพมากขึ้นโดยให้ผู้ใช้เลือกรูปแบบเอฟเฟกต์แก้ไขระยะเวลาเรียกบางสิ่งบางอย่างเมื่อภาพเคลื่อนไหวเสร็จสมบูรณ์แท็กมุมมองเอฟเฟกต์ภาพที่เพิ่มเข้ามาในภาพเบลอ () เพื่อให้แน่ใจว่าเป็นเพียงภาพเดียวที่ถูกลบออกเมื่อคุณไม่เบลอ ( ) เป็นต้น แต่ตอนนี้ฉันยังไม่พบว่าจำเป็นต้องทำสิ่งเหล่านี้เนื่องจากมีแนวโน้มที่จะเป็นการดำเนินการประเภท "ไฟแล้วลืม"


"fire and forget" สัมพันธ์กันมาก! ฮา
LinusGeffarth

0

ตามคำตอบของ @ cc ฉันแก้ไขส่วนขยายของเขาเพื่อเบลอมุมมอง

นามสกุล UIView {

    func เบลอ () {
        // เบลอมุมมองปัจจุบัน
        ให้เบลอView = UIVisualEffectView (เฟรม: self.bounds)
        self.addSubview (เบลอวิว)
        UIView.animate (withDuration: 0.25) {
            เบลอView.effect = UIBlurEffect (สไตล์: .dark)
        }
    }

    func unblur () {
        สำหรับ childView ใน subviews {
            guard ให้ effectView = childView เป็น? UIVisualEffectView else {ต่อ}
            UIView.animate (withDuration: 2.5, ภาพเคลื่อนไหว: {
                effectView.effect = ศูนย์
            }) {
                ทำเสร็จใน
                effectView.removeFromSuperview ()
            }
        }
    }
}

0

การปรับปรุงการตอบสนอง @ Tel4tel และ @cc นี่คือส่วนขยายที่มีพารามิเตอร์และคำอธิบายสั้น ๆ

extension UIView {

    // Perform a blur animation in the whole view
    // Effect tone can be .light, .dark, .regular...
    func blur(duration inSeconds: Double, effect tone: UIBlurEffectStyle) {
        let blurView = UIVisualEffectView(frame: self.bounds)
        self.addSubview(blurView)
        UIView.animate(withDuration: inSeconds) {
            blurView.effect = UIBlurEffect(style: tone)
        }
    }

    // Perform an unblur animation in the whole view
    func unblur(duration inSeconds: Double) {
        for childView in subviews {
            guard let effectView = childView as? UIVisualEffectView else { continue 
        }
            UIView.animate(withDuration: inSeconds, animations: {
                effectView.effect = nil
            }){
                didFinish in effectView.removeFromSuperview()
            }
        }
    }
}

จากนั้นคุณสามารถใช้มันเช่น: view.blur(duration: 5.0, effect: .light) หรือ view.unblur(duration: 3.0)

อย่าลืมใช้ในviewDidLoad()เนื่องจากจะลบล้างภาพเคลื่อนไหว นอกจากนี้เมื่อทำงานบนเครื่องจำลองให้เปลี่ยนกราฟิกเป็นระดับที่สูงขึ้นเพื่อให้สามารถดูภาพเคลื่อนไหวได้ (แก้ไขข้อบกพร่อง> การแทนที่คุณภาพกราฟิก> คุณภาพสูง)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.