UIVisualEffectView in a UITableViewCell breaks when deleting a cell - ios

I have created a UITableViewController and each cell has a blur effect applied to them using UIVisualEffectView. I also have a blurred background that is created in the UITabBarViewController that the table view is linked to. The extra blur effect applied to each cell adds a nice touch to the UI I am designing, and it works for the most part.
The Issue
Everything works fine until I delete an item from the table. Doing so causes the whole table view to appear damaged. Everything returns to normal after the delete animation has been completed.
I have tried applying the UIVisualEffectView via code and the storyboard, and the problem is consistent either way. When using code, I apply the effect here like this:
// 'cell' is the cell being configured in tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
visualEffectView.frame = cell.bounds
cell.insertSubview(visualEffectView, atIndex: 0)
Note: After doing more testing, I have narrowed down the problem. When setting a cell to a clear color via the storyboard or in code using cell.backgroundColor = UIColor.clearColor(), the damaged animation appears. In fact, it does this for any color that has some, or complete transparency. When there is no transparency, the issue stops, but then the background from the UITabBarController is no longer visible.
My Question
How can I fix the damaged animation while keeping a similar/same look?
And if you want to see how I added the blur to the UITableViewController, here it is:
class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
imageView = UIImageView(image: UIImage(named: "Sunset"))
imageView.frame = self.view.bounds
imageView.contentMode = .ScaleAspectFill
view.insertSubview(imageView, atIndex: 0)
let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.frame = imageView.bounds
view.insertSubview(blurEffectView, aboveSubview: imageView)
}
//...
And here is what damaged animation looks like on the simulator (same thing happens on a physical device too):

Related

UIBlurEffect not blurring entire image in UITableViewCell

I have the following code to blur out an image.
let blurEffect = UIBlurEffect(style: .light)
let blurredEffectView = UIVisualEffectView(effect: blurEffect)
blurredEffectView.frame = imageBlur.bounds
//blurredEffectView.alpha = 0.8
imageBlur.addSubview(blurredEffectView)
imageBlur.sd_setImage(with: URL(string: item._galleryURL), placeholderImage: UIImage(named: ""))
However, when I run the code, I am seeing this for the first two elements in the UITableView.
When I scroll down and then back up again, they will fix...
What can be causing this bug?
When you create the blur view in tableView cell you the view not now the exact size. So in the first create of screen it looks not okay but when you scroll down and up it recycles and know it size it becomes okay.
So you can solve it by giving size in layoutsubviews() function like
override func layoutSubviews() {
super.layoutSubviews()
blurredEffectView.frame = imageBlur.bounds
}

Swift 5 custom navigation bar cover title and buttons

After seeking a lot and trying many solutions, nope fixed my problem.
In my app I customized the UINavigationController in order to have blur effect:
import UIKit
class CustomNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.frame = (self.navigationBar.bounds.insetBy(dx: 0, dy: -40).offsetBy(dx: 0, dy: -40))
self.navigationBar.isTranslucent = true
self.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationBar.addSubview(visualEffectView)
self.navigationBar.sendSubviewToBack(visualEffectView)
}
}
Then in Main.storyboard I selected the customized class for the navigation controller item.
The blur effect works properly, the status icons are correctly visible, but not the standard navigation bar items: left button, title and right button.
For a moment they appears but soon after the customized navigation bar covers them.
I'm using Xcode 12.4 and I'm running the app on iPhone Xr.
How can I show the navigation bar elements again?
Thanks a lot in advance.
Translucent navigation bars in iOS already blur the content behind the bar, so you shouldn't need to add a UIVisualEffectView nor set a backgroundImage.
If you modify your code to just:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationBar.isTranslucent = true
}
does this not achieve the visual effect you're looking for?
If not, please try the following adjustment to your methodology:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationBar.isTranslucent = true
// create a UIImageView
let backgroundImage: UIImageView = UIImageView()
backgroundImage.autoresizingMask = [.flexibleWidth, .flexibleHeight]
backgroundImage.image = UIImage()
// add a blur effect to the ImageView
let visualEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.frame = (self.navigationBar.bounds.insetBy(dx: 0, dy: -40).offsetBy(dx: 0, dy: -40))
backgroundImage.addSubview (visualEffectView)
// and set that as your backgroundImage on the navigationBar
self.navigationBar.setBackgroundImage(backgroundImage.image, for: .default)
}
this adds the blur effect to the backgroundImage. This seems to work for me, but the visual effect is no different than just using my first suggestion, likely because backgroundImage.image == nil.
This is certainly an improved approach in that it doesn't add unexpected subviews into the UINavigationBar view hierarchy, and I observed both methods did not affect the visibility of the bar controls.

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

Grid layout with CollectionView in Swift

I would like to achieve this result:
Searching around I found out that probably the way to do it is using UICollectionView, so no problem with that since there are many tutorials and questions on Stack Overflow. I have 3 questions:
I cannot find anything about the "separators" (the line that divides all the boxes). I like that it doesn't touch the screen borders horizontally. Is it done programmatically?
To divide the space equally in all devices (3 boxes/buttons horizontally) I found this answer answer. Is this the right approach?
For the Blur effect I found this answer: How to implement UIVisualEffectView in UITableView with adaptive segues
For a TableView it would be:
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
tableView.backgroundColor = UIColor.clearColor()
let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
tableView.backgroundView = blurEffectView
}
Can I do something like this?
#IBOutlet var collectionView: UICollectionView!
if (!UIAccessibilityIsReduceTransparencyEnabled()) {
collectionView.backgroundColor = UIColor.clearColor()
let blurEffect = UIBlurEffect(style: .Light)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
collectionView.backgroundView = blurEffectView
}
Create the UICollectionViewController like this in a file that sub-classes from UICollectionViewController:
convenience override init() {
var layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSizeMake(<width>, <height>)
// Setting the space between cells
layout.minimumInteritemSpacing = <Space between columns>
layout.minimumLineSpacing = <Space between rows>
return (self.init(collectionViewLayout: layout))
}
In the viewDidLoad you an set the background color like this:
self.collectionView.backgroundColor = UIColor.orangeColor()
My guess is you can set a background image like this:
self.collectionView?.backgroundColor = UIColor(patternImage: UIImage(named: "image.png")!)
The blur effect that you found looks good. I am having trouble figuring out how it would work though. Probably set it using the backgroundView property.
I'll update if I find the answer.
Update:
Here is an idea of something that might work for blurring the cells.
Create a cocoa-touch class that sub-classes from UICollectionViewCell, then add this code to it:
convenience override init(frame: CGRect) {
self.init(frame: frame)
var blurEffect: UIVisualEffect
blurEffect = UIBlurEffect(style: .Light)
var visualEffectView: UIVisualEffectView
visualEffectView = UIVisualEffectView(effect: blurEffect)
visualEffectView.frame = self.maskView!.bounds
self.addSubview(visualEffectView)
}
override func layoutSubviews() {
super.layoutSubviews()
self.maskView!.frame = self.contentView.bounds
}
Then in the CollectionViewController file, in the viewDidLoad, change this line of code:
self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
Change UICollectionViewCell.self to <Name of CollectionViewCell file>.self
Result:
1) First of all, I think you need to change how you look at that layout. There are no separators. Just UICollectionView Cells with spacing between cells, lowered opacity and some blur.
This settings will give you something close to image you posted, you can edit it for your needs later:
On storyboard go to your UICollectionView's size inspector.
Min Spacing-> For Cells = 2, For Lines = 2.
Section Insets-> Left = 7, Right = 7.
2) I'm using this on my app to divide space equally for 3 cells. Changed it for your settings. Just copy/paste and you are good to go.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
return CGSize(width: (screenWidth/3)-6, height: (screenWidth/3)-6);
}
}
And as the last step put two images on top of CollectionView, to the left and right of the view and make widths equal to 7 and heights equal to UICollectionView. These images should have same opacity/background with cells. This will make it look like the image you want.
I hope my answer works for you. Good luck.
The first thing I would like to say is, your all above result can be achieved from UICollectionViewFlowLayout, Which is the default layout for UICollectionView.
UICollectionViewDelegateFlowLayout has all of the methods that can fulfill your requirements.
The flowLayout has minimumLineSpacingForSectionAtIndex and minimumInteritemSpacingForSectionAtIndexfor giving the spacing between the cells(both horizontally and vertically).
Its not a good way of giving cell frame in cellForItemAtIndexPath (like you submit the answer link). For that flowLayout provides a delegate for sizing cell sizeForItemAtIndexPath.
About the third question, yes you can use UIVisualEffectView for bluring purpose but compatible for only after iOS 8 and has issue with iPad2 I guess. But for your problem I would blur each cell rather than collectionView itself(since cell spacing is not blur).
I cannot find anything about the "separators" (the line that divides all the boxes). I like that it doesn't touch the screen borders horizontally. Is it done programmatically?
Yes, it looks like it is rendered on to a layer. You should read the Quartz 2D Programming Guide to get a handle on drawing and working with layers.
To divide the space equally in all devices (3 boxes/buttons horizontally) I found this answer answer. Is this the right approach?
This would be an option, but would not give you the separators look you like from your screen shot.
I would have my cell view's backgroundColor is set to clearColor, and then set the UICollectionView's backgroundView property to a view containing your separators and the blur effect. Make sure the UICollectionView's backgroundColor property is set to clearColor.
About the third question, yes you can use UIVisualEffectView for bluring purpose but compatible for only after iOS 8 and has issue with iPad2 I guess. But for your problem I would blur each cell rather than collectionView itself(since cell spacing is not blur).
If you use the backgroundView property of the UICollectionView to handle your separators and blur then your cells would only need to have their backgroundColor set to clearColor.
You should note that there is more than one way to do this, each way will have it's own drawbacks choose what works for you best.
I have created this meethod for custom layout. You can use by modifying according to your request.
func setCollectionLayout() {
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top:0,left:0,bottom:0,right:0)
layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width/2 - 1, height: 136)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
collectionView.collectionViewLayout = layout
}

TableView with image background and blur effect - swift

I have a little problem: I'd like to set an image to background in a TableViewController. I tried this:
class SquadreController: UITableViewController {
override func viewDidLoad()
{
super.viewDidLoad()
var sfondo = UIImage(named: "sfondo")
self.view.backgroundColor = UIColor(patternImage: sfondo!)
}
Then I give the blur effect to the view, like this:
let blur = UIBlurEffect(style: UIBlurEffectStyle.Light)
let blurView = UIVisualEffectView(effect: blur)
blurView.frame = self.view.bounds
view.addSubview(blurView)
But there is a big problem. I'm working in a TableView and the TableView, TableCell, NavigationItem, etc. have all disappeared after I apply the blur. Can someone help me?
Thanks a lot!
Try using view.insertSubView(blurView, atIndex: 0) instead of view.addSubview(blurView) as! UIImageView
This question is an older question and Epic Defeater's response does in a way work, there is a much better way to accomplish this. Instead of adding blurView, you need to override the background view. Specifically you need to override tableView.backgroundView.
let blur = UIBlurEffect(style: .light)
let blurView = UIVisualEffectView(effect: blur)
blurView.frame = self.view.bounds
tableView.backgroundView = blurView
This will only work if you have set the background color to clear.
We can also add a subview below or above any other views using insertSubview
//Inserting below your subView
self.view.insertSubview(subview1_name, belowSubview: subview2_name)
//Inserting above your subView
self.view.insertSubview(subview1_name, aboveSubview: subview2_name)
/// You can use any of your view, instead of self.view

Resources