Using UIScrollView with UIVisualEffectView (UIBlurEffect) in Swift - ios

I'm using UIBlurEffect from UIVisualEffectView to produce the look introduced in iOS 7. To do so I programmatically add anything I want portrayed on top of the blur to the contentView, as described in the UIBlurEffect Class Reference:
A UIBlurEffect object applies a blurring effect to the content layered
behind a UIVisualEffectView. Views added to the contentView of a
UIVisualEffectView are not affected by the blur effect.
But now I need to add a UIScrollView into the mix, and the fact that I had to use the contentView has left me completely confused. I'm not very familiar with the UIScrollView, but the iOS 8 Swift Programming Cookbook gives this example:
I'm not in need of displaying an imageView, but instead a separate view with many views inside of it in the hierarchy. Where exactly do I add the scrollView? Do I set scrollView as a subview of contentView? Or the other way around, the contentView as a subview of scrollView? Here's my current code:
class InfoVC: UIViewController {
#IBOutlet weak var contentView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// blur
let blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
blur.frame = view.frame
view.addSubview(blur)
blur.contentView.addSubview(self.contentView)
}

You want to scroll something on top of the blur effect, correct?
In that case you need to add the scroll view to the content view of the blur view.
Assuming the contentView is the view you want to scroll it should work like this:
let blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
blur.frame = view.bounds
view.addSubview(blur)
UIScrollView scrollView = UIScrollView(frame:blur.bounds)
blur.contentView.addSubview(scrollView)
scrollView.addSubview(contentView)
scrollView.contentSize = contentView.frame.size // or whatever other size you like

Related

Pan Large Image in Scrollview through StoryBoard

I am building an application where I want to display a floor plan where the image is 2952x3600, larger than the size of my view controller. I want the user to be able to pan the image and zoom in and out, similar to how a map behaves in Mapview.
I was able to obtain the desired result programmatically with the below code. However, I want to be able to add buttons to the image and it will be easier to do in the storyboard. How can I accomplish the same result in the Storyboard?
class ViewController: UIViewController, UIScrollViewDelegate {
var scrollView: UIScrollView!
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView(image: UIImage(named: "TorontoPATHNetworkMap_v.2018.08.pdf"))
scrollView = UIScrollView(frame: view.bounds)
scrollView.contentSize = imageView.bounds.size
scrollView.addSubview(imageView)
scrollView.delegate = self
scrollView.minimumZoomScale = 0.3
scrollView.maximumZoomScale = 5
view.addSubview(scrollView)
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
}
If you want to add other UI elements (buttons, labels, subviews, etc) and have them scale and move when the scroll view content is zoomed, you have a couple options:
1) Add your buttons in code as subviews of the image view. They will move / size along with the image view.
2) If you'd find it easier to layout your buttons visually, you can do your layout in Storyboard / Interface Builder. In IB, though, you cannot add subviews to a UIImageView, so you will need to embed the image view and buttons in a "container" UIView. Then in your controller class return that container view from viewForZooming
Edit
Here's an example of setting up the views in Storyboard / IB: https://github.com/DonMag/PDFImagePanZoom

Blurred UIImageView Sizing Problems

A UIViewController I'm presenting has a UIImageView, namely backgroundImageView, to be the VC's background and set to fill the whole screen.
I want the UIImageView to be presented with a dark blur effect provided by iOS but the following sizing issue temporarily occurs(on device but not on the simulator) when I first present the view controller:
Inside viewDidLoad():
// `locationImage` is passed during the segue
backgroundImageView.image = locationImage
backgroundImageView.contentMode = .scaleAspectFill
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = backgroundImageView.bounds
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
backgroundImageView.addSubview(blurEffectView)
The above view controller's modalPresentationStyle is set to be as currentContext.
If I temporarily remove the blur effect, I see that the background image I gave the view controller got properly set. However once the blur effect is applied, sizing issues occur momentarily.
What exactly is causing this?
Try to set the frame of blurEffectView inside viewWillLayoutSubviews() or in viewDidLayoutSuviews()
here you can find more information about viewcontroller's lifecycle

Blur effect does not fill the entire View

I have a View controller that features a full screen UIImageView. When the controller loads, I just set a blur effect over the whole screen. The content mode for the UIImageView is set to scaleAspectFill. I set the blur effect like this:
#IBOutlet weak var previewImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
previewImage.image = userPhoto
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
blur.frame = self.view.bounds
previewImage.addSubview(blur)
}
when I test the app on an iPhone 6 I get this result:
There's an offset on the right an I can't figure out why. The picture underneath if is properly full screened but I can get the blur effect to fit over it...
****EDITED****
I applied the blur effect to the VC's view directly and now it works just fine, but I'd like to know why it doesn't work when I add the subview to the UIImage View...
I see two possible problems here:
Views are not laid out on the viewDidLoad stage. In this case you can force them to layout manualy:
override func viewDidLoad() {
super.viewDidLoad()
self.view.layoutIfNeeded()
...
}
You add subview to the previewImage, not to the root view. You must check your storyboard, or fix code:
override func viewDidLoad() {
super.viewDidLoad()
previewImage.image = userPhoto
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
blur.frame = self.view.bounds
self.view.insertSubview(blur, aboveSubview: previewImage)
}
Based on #kelin answer. You can even add the blur effect above your image in the interface builder.Just search for Visual Effect View with Blur in the objects section in the interface builder. Then add the Visual Effect View view above your image. It is also fully customizable through Attributes inspector. That way you you make sure that the blur will occupy the entire screen. It is also cleaner from architecture perspective , you do not need to configure your view through code.

Adding Subview To UIViewController Makes UITablview Subview Disappear

This code is called inside of a function that is called programatically. The UITableView that it is inserted over has been put in the UIViewController in a storyboard. The UIViewController is embedded in a navigationController.
let containerView = UIView()
containerView.frame.size.width = self.view.frame.width / 2
containerView.frame.size.height = self.view.frame.width / 2
let blurEffect = UIBlurEffect(style: .Dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = containerView.bounds
containerView.center = self.view.center
containerView.addSubview(blurEffectView)
self.view.insertSubview(containerView, aboveSubview: matchTableView)
indicator?.startAnimation()
I'm just trying to add an activity indicator over the tableview. The actual activity indicator shows up just fine but I need to put a background behind it so it can be seen correctly. As soon as any type of subview is added to the UIViewController the table disappears.
Have you tried:
let containerView = UIView()
...
containerView.opaque = false
containerView.backgroundColor = UIColor.clearColor()
The tableView is disappearing because you are inserting the container view
above it .
You nedd to add your activity indictor above the table view , where the activity indicator view frame is less than the table view frame
matchTableView.addSubView(containerView)
Previously I had been adding the subview in a function long after the view rendered itself. The way to get this done was to add the view in viewDidAppear. After that I could manipulate it any way I needed. Any period after viewDidAppear in the life cycle and the tableView disappears. I don't know why or if this is the correct way to avoid that issue but this works as a solution.
Adding it in viewDidLoad does not add it to the render tree. It will be there but it will have been too early for it to display properly.

UITableViewController Blur Background Not Showing With Scroll

I have set a background image for my UITableViewController and then added a blur effect with the following code:
var blur = UIBlurEffect(style: UIBlurEffectStyle.Dark)
var blurView = UIVisualEffectView(effect: blur)
blurView.frame = self.view.bounds
self.view.insertSubview(blurView, atIndex: 0)
When I scroll down, the background image is still there but the blur effect is only there for the first few cells that fit into the view at a time. How can I make it so the blur effect is there as I scroll?
I tried adding the blur effect to each cell, but that makes it look really weird.
For UITableViewControllers self.view is the UITableView it self. That means any subview you add to self.view will scroll along with the content of the table view.
You could either make an own UIViewController, set up UITableView manually and place it in front of the blur view (instead of placing the blur view inside the table view) or you could move the blur view's location when the table view is scrolled.
To move the blur view to compensate for the table view's offset you can do something like this:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
var blurViewFrame = CGRect()
blurViewFrame.size = view.bounds.size
blurViewFrame.y = tableView.contentOffset.y
blurView.frame = blurViewFrame
}

Resources