web-dev-qa-db-ger.com

Weniger Unschärfe mit visueller Effektansicht mit Unschärfe?

Titel fragt so ziemlich alles ...

Ich spiele mit dem iOS8 Visual Effect View with Blur. Es ist ein UIImageView, der ein vom Benutzer wählbares Hintergrundfoto zeigt. Die in der contentView selbst platzierte Ansicht ist meine eigene benutzerdefinierte Ansicht. Sie zeigt eine Art Diagramm/Kalender. Die meisten Kalenderdiagramme sind transparent. Die Unschärfe, die auf das Foto dahinter angewendet wird, ist sehr schwer. Ich würde gerne mehr Detail durchlassen. Aber Apple scheint nur drei Werte zu nennen:

typedef enum {
    UIBlurEffectStyleExtraLight,
    UIBlurEffectStyleLight,
    UIBlurEffectStyleDark 
} UIBlurEffectStyle;

Ich habe mit verschiedenen Alphas und Hintergrundfarben von UIVisualEffectView herumgemuntert (obwohl die Dokumentation davor warnt), aber das macht nichts anderes, als es noch schlimmer zu machen.

21
Travis Griggs

Der Grund, warum Sie starke Unschärfe erhalten, besteht darin, dass der Stil des Unschärfeeffekts die Helligkeit von Helligkeit des Bildes beeinflusst und nicht die Menge der angewendeten Unschärfe. 

enter image description here

Obwohl Apple eindeutig die Möglichkeit hat, die programmgesteuerte Unschärfe zu steuern, ziehen Sie das Launchpad langsam nach unten, um den Übergang zwischen Spotlight und Unschärfe zu beobachten. Ich sehe keine öffentliche API, um einen Unschärfebetrag an UIBlurEffect zu übergeben.

Dieser Beitrag behauptet, dass das Anpassen der Hintergrundfarbe Alpha den Unschärfebetrag beeinflusst. Es ist einen Versuch wert, aber ich sehe nicht, wo das dokumentiert ist: Wie kann ich ein UIVisualEffectView und/oder UIBlurEffect ein- und ausblenden?

28
StilesCrisis

Es ist schade, dass Apple keine Optionen für Unschärfeeffekte zur Verfügung gestellt hat. Dieser Workaround hat jedoch für mich funktioniert - den Unschärfeeffekt animieren und vor der Fertigstellung anhalten.

func blurEffectView(enable enable: Bool) {
    let enabled = self.blurView.effect != nil
    guard enable != enabled else { return }

    switch enable {
    case true:
        let blurEffect = UIBlurEffect(style: .ExtraLight)
        UIView.animateWithDuration(1.5) {
            self.blurView.effect = blurEffect
        }

        self.blurView.pauseAnimation(delay: 0.3)
    case false:
        self.blurView.resumeAnimation()

        UIView.animateWithDuration(0.1) {
            self.blurView.effect = nil
        }
    }
}

und die UIView-Erweiterungen zum Anhalten (mit Verzögerung) und zum Fortsetzen der Animation der Ansicht

extension UIView {

    public func pauseAnimation(delay delay: Double) {
        let time = delay + CFAbsoluteTimeGetCurrent()
        let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, { timer in
            let layer = self.layer
            let pausedTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
            layer.speed = 0.0
            layer.timeOffset = pausedTime
        })
        CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
    }

    public func resumeAnimation() {
        let pausedTime  = layer.timeOffset

        layer.speed = 1.0
        layer.timeOffset = 0.0
        layer.beginTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
    }
}
40
mitja13

Das funktioniert für mich.

Ich füge UIVisualEffectView in eine UIView ein, bevor ich sie meiner Ansicht hinzufüge.

Ich mache diese Funktion einfacher zu benutzen. Mit dieser Funktion können Sie beliebige Bereiche in Ihrer Ansicht verwischen.

func addBlurArea(area: CGRect, style: UIBlurEffectStyle) {
    let effect = UIBlurEffect(style: style)
    let blurView = UIVisualEffectView(effect: effect)

    let container = UIView(frame: area)
    blurView.frame = CGRect(x: 0, y: 0, width: area.width, height: area.height)
    container.addSubview(blurView)
    container.alpha = 0.8
    self.view.insertSubview(container, atIndex: 1)
}

Sie können beispielsweise Ihre gesamte Ansicht verwischen, indem Sie Folgendes aufrufen:

addBlurArea(self.view.frame, style: UIBlurEffectStyle.Dark)

Sie können Dark in Ihren gewünschten Unschärfestil und 0.8 in Ihren gewünschten Alpha-Wert ändern 

8

Ja, du kannst.

Hier ist ein Beispiel für eine UIImageView mit Unschärfeeffekt. Denken Sie daran, der UIImageView ein Bild hinzuzufügen.

Anpassen der Unschärfemenge mit blurEffectView.alpha = 0,8 (von 0 bis 1)

import UIKit

class BlurEffectImageView: UIImageView {

override func awakeFromNib() {
    super.awakeFromNib()
    addBlurEffect()
}

private func addBlurEffect(){
    let blurEffect = UIBlurEffect(style: .light)
    let blurEffectView = UIVisualEffectView(effect: blurEffect)
    blurEffectView.alpha = 0.8

    blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

    blurEffectView.translatesAutoresizingMaskIntoConstraints = false
    addSubview(blurEffectView)

    NSLayoutConstraint(item: blurEffectView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0).isActive = true
    NSLayoutConstraint(item: blurEffectView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true
    NSLayoutConstraint(item: blurEffectView, attribute: .height,  relatedBy: .equal, toItem: self, attribute: .height,  multiplier: 1.0, constant: 0).isActive = true
    NSLayoutConstraint(item: blurEffectView, attribute: .width,   relatedBy: .equal, toItem: self, attribute: .width,   multiplier: 1.0, constant: 0).isActive = true
  }

}
5
alegelos

Fügen Sie eine BlurEffectView zu einer Ansicht mit Alpha <1 der Ansicht hinzu

func addBlurEffectView() -> Void {
    if !UIAccessibilityIsReduceTransparencyEnabled() {
        let viewContainer = UIView()
        viewContainer.frame = self.view.bounds
        viewContainer.alpha = 0.5

        let blurEffect = UIBlurEffect(style: .dark)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.layer.zPosition = -0.5;
        blurEffectView.frame = self.view.bounds;
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        viewContainer.addSubview(blurEffectView)

        self.view.addSubview(viewContainer)
        self.view.sendSubview(toBack: viewContainer)
    }
}
1
Tà Truhoada

Ich verwende UIVisualEffectView so, um einstellbare Unschärfekreise zu erhalten. Die Unschärfe wird durch einen Schieberegler gesteuert, der das Alpha steuert. Ich werde auch den Slider-Handler unten einfügen. Die Größe des Unschärfekreises ist mit der Prise Spread-Aktion einstellbar. Ich werde das auch einschließen. Und Sie können die Unschärfekreise ziehen. Ich lasse das als Übung für den Leser. Wenn Sie ein Unschärfe-Rechteck wünschen, runden Sie die Ecken nicht ab. Laden Sie die MemeSoEasy-App (kostenlos) herunter, fügen Sie ein Foto hinzu (mit dem Sie einen Unschärfekreis darüber legen können), und fügen Sie dann einen Unschärfekreis hinzu.

UIVisualEffectView *blurVisualEffectView;

UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
blurVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurVisualEffectView.frame = lastChosenBlurCircleRect;
blurVisualEffectView.center = CGPointMake(halfScreenX, halfScreenY);
[self.view addSubview:blurVisualEffectView];
CGFloat blurCornerRadius = blurVisualEffectView.bounds.size.width/2;
[[blurVisualEffectView layer]setCornerRadius:blurCornerRadius];
[[blurVisualEffectView layer]setMasksToBounds:YES];
[[blurVisualEffectView layer] setBorderWidth:4.0f];
[[blurVisualEffectView layer] setBorderColor:[UIColor blueColor].CGColor];
blurVisualEffectView.userInteractionEnabled = NO;
blurVisualEffectView.alpha = 0.97;
[blurArray addObject:blurVisualEffectView];

Slider-Handler: 

Beachten Sie, dass ich meine Unschärfobjekte in einem Array speichere, sodass Benutzer beliebig viele erstellen können. Der Schieberegler behandelt das letzte Objekt im Array. Die minimalen und maximalen Werte des Schiebereglers betragen 0,0 und 1,0

UISlider *slider_ = (UISlider *)sender;
CGFloat ourSliderValue = slider_.value;
UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];
currentBlurObject.alpha = ourSliderValue;

Größenänderungs-Handler für Prise Spread

int changeInWidth = 0; // one pixel at a time

if (pinchGesture.scale > 1.0) {
    changeInWidth++;
}
if (pinchGesture.scale < 1.0) {
    changeInWidth--;
}

UIVisualEffectView *currentBlurObject =
[blurArray objectAtIndex:blurArray.count - 1];

CGPoint oldCenter = currentBlurObject.center;

currentBlurObject.frame = CGRectMake(0, 0, currentBlurObject.frame.size.width + changeInWidth, currentBlurObject.frame.size.width + changeInWidth);

currentBlurObject.center = oldCenter;

lastChosenBlurCircleRect = currentBlurObject.frame;

CGFloat blurCornerRadius = currentBlurObject.frame.size.width/2;
[[currentBlurObject layer]setCornerRadius:blurCornerRadius];
1
user3408691

Um Unschärfe mit Unschärfegrad zu verwenden, verwende meine Erweiterung wie folgt:

public extension UIView {
  func applyBlur(level: CGFloat) {
    let context = CIContext(options: nil)
    self.makeBlurredImage(with: level, context: context, completed: { processedImage in
      let imageView = UIImageView(image: processedImage)
      imageView.translatesAutoresizingMaskIntoConstraints = false
      self.addSubview(imageView)
      NSLayoutConstraint.activate([
        imageView.topAnchor.constraint(equalTo: self.topAnchor),
        imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
        imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
        imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
      ])
    })
  }

  private func makeBlurredImage(with level: CGFloat, context: CIContext, completed: @escaping (UIImage) -> Void) {
    // screen shot
    UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 1)
    self.layer.render(in: UIGraphicsGetCurrentContext()!)
    let resultImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    let beginImage = CIImage(image: resultImage)

    // make blur
    let blurFilter = CIFilter(name: "CIGaussianBlur")!
    blurFilter.setValue(beginImage, forKey: kCIInputImageKey)
    blurFilter.setValue(level, forKey: kCIInputRadiusKey)

    // extend source image na apply blur to it
    let cropFilter = CIFilter(name: "CICrop")!
    cropFilter.setValue(blurFilter.outputImage, forKey: kCIInputImageKey)
    cropFilter.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")

    let output = cropFilter.outputImage
    var cgimg: CGImage?
    var extent: CGRect?

    let global = DispatchQueue.global(qos: .userInteractive)

    global.async {
      extent = output!.extent
      cgimg = context.createCGImage(output!, from: extent!)!
      let processedImage = UIImage(cgImage: cgimg!)

      DispatchQueue.main.async {
        completed(processedImage)
      }
    }
  }
}

Wie benutzt man. Führen Sie es aus, wenn der Frame bereits angezeigt wurde. Zum Beispiel in viewDidAppear:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    myView.applyBlur(level: 5)
}
0
Leonif

Eine Lösung, die einigen hier ähnelt, aber einfacher ist, besteht darin, einen UIViewPropertyAnimator (iOS 10+) zu verwenden und seine fractionComplete-Eigenschaft auf einen Wert zwischen 0 und 1 festzulegen.

    // add blur view to image view
    let imgBlur = UIVisualEffectView()
    imgView.addSubview(imgBlur)
    imgBlur.frame = imgView.bounds

    // create animator to control blur strength
    let imgBlurAnimator = UIViewPropertyAnimator()
    imgBlurAnimator.addAnimations {
        imgBlur.effect = UIBlurEffect(style: .dark)
    }

    // 50% blur
    imgBlurAnimator.fractionComplete = 0.5

Wenn Sie fractionComplete basierend auf einer Schwenkgeste, einer Bildlaufansicht, einem Schieberegler usw. variieren möchten, müssen Sie pausesOnCompletion = true (iOS 11+) festlegen.

0
pinch

Diese Antwort basiert auf Mitja Semolics hervorragender früherer Antwort . Ich habe es in Swift 3 konvertiert, eine Erklärung zu den Ereignissen in Kommentaren hinzugefügt, es als Erweiterung eines UIViewControllers definiert, sodass jeder VC es nach Belieben aufrufen kann, eine unscharfe Ansicht hinzugefügt, um die selektive Anwendung anzuzeigen, und eine Completion-Block, damit der aufrufende View-Controller nach Beendigung der Unschärfe alles tun kann, was er will.

    import UIKit
//This extension implements a blur to the entire screen, puts up a HUD and then waits and dismisses the view.
    extension UIViewController {
        func blurAndShowHUD(duration: Double, message: String, completion: @escaping () -> Void) { //with completion block
            //1. Create the blur effect & the view it will occupy
            let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.light)
            let blurEffectView = UIVisualEffectView()//(effect: blurEffect)
            blurEffectView.frame = self.view.bounds
            blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        //2. Add the effect view to the main view
            self.view.addSubview(blurEffectView)
        //3. Create the hud and add it to the main view
        let hud = HudView.getHUD(view: self.view, withMessage: message)
        self.view.addSubview(hud)
        //4. Begin applying the blur effect to the effect view
        UIView.animate(withDuration: 0.01, animations: {
            blurEffectView.effect = blurEffect
        })
        //5. Halt the blur effects application to achieve the desired blur radius
        self.view.pauseAnimationsInThisView(delay: 0.004)
        //6. Remove the view (& the HUD) after the completion of the duration
        DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
            blurEffectView.removeFromSuperview()
            hud.removeFromSuperview()
            self.view.resumeAnimationsInThisView()
            completion()
        }
    }
}

extension UIView {
    public func pauseAnimationsInThisView(delay: Double) {
        let time = delay + CFAbsoluteTimeGetCurrent()
        let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, time, 0, 0, 0, { timer in
            let layer = self.layer
            let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil)
            layer.speed = 0.0
            layer.timeOffset = pausedTime
        })
        CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, CFRunLoopMode.commonModes)
    }
    public func resumeAnimationsInThisView() {
        let pausedTime  = layer.timeOffset

        layer.speed = 1.0
        layer.timeOffset = 0.0
        layer.beginTime = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime
    }
}

Ich habe bestätigt, dass es sowohl mit iOS 10.3.1 als auch mit iOS 11 funktioniert

0