UIView not being removed from UIWindow - ios

I have a UIView() added to UIApplication.shared.keyWindow so it covers the screen in totality.
To that UIView I add as sublayer a gradient color (which I think it's not causing the problem here).
After some initial setup I try to remove this view with removeFromSuperview() call but it doesn't get removed.
I'm dispatching on main because I'm making this removal call in a background thread.
Here's the related code:
Adding the view to keyWindow
fileprivate func addOverlapView() {
let frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.overlapView = UIView(frame: frame)
let overlapGradient: CAGradientLayer = CAGradientLayer()
overlapGradient.colors = [self.fromColor.cgColor, self.toColor.cgColor]
overlapGradient.locations = [0.0, 1.0]
overlapGradient.frame = self.view.bounds
overlapGradient.masksToBounds = true
overlapView.layer.insertSublayer(overlapGradient, at: 0)
let textLabel = UILabel()
textLabel.text = "Configuring user settings"
textLabel.textAlignment = .center
textLabel.textColor = .white
overlapView.addSubview(textLabel)
textLabel.anchor(top: nil, left: nil, bottom: nil, right: nil, paddingTop: 0, paddinfLeft: 0, paddingBottom: 0, paddingRight: 0, width: overlapView.frame.width, height: 100)
textLabel.centerXAnchor.constraint(equalTo: overlapView.centerXAnchor).isActive = true
textLabel.centerYAnchor.constraint(equalTo: overlapView.centerYAnchor).isActive = true
UIApplication.shared.keyWindow?.addSubview(overlapView)
}
And then I'm trying to remove it with the following call:
DispatchQueue.main.async {
self.overlapView.removeFromSuperview()
}
But somehow the view doesn't get removed.
Any hint on what may be causing this?

Related

UIScrollView inside of UIViewController not scrolling horizontally

I have created a UIScrollView inside of a UIViewController. I have added a UIView inside of my UIScrollView with one label inside of the UIView. The plan is to eventually add 3 very large UIButtons that is why I need a scroll view. I have not used storyboard and it is done all programmatically. I cannot get the UIScrollView to work.
class ChooseCategoryPostViewController: UIViewController, UIScrollViewDelegate {
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.backgroundColor = .green
return sv
}()
let myView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
let test: UILabel = {
let label = UILabel()
label.text = "test label"
label.font = UIFont.boldSystemFont(ofSize: 15)
label.textAlignment = .center
return label
}()
override func viewDidLoad() {
view.addSubview(scrollView)
scrollView.addSubview(myView)
scrollView.anchor(top: topTitle.bottomAnchor, left: nil, bottom: nil, right: nil, paddingTop: 200, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: view.frame.width, height: 200)
myView.anchor(top: scrollView.topAnchor, left: scrollView.leftAnchor, bottom: scrollView.bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 10, paddingBottom: 0, paddingRight: 0, width: 1700, height: 200)
myView.addSubview(test)
test.anchor(top: myView.topAnchor, left: nil, bottom: nil, right: myView.rightAnchor, paddingTop: 20, paddingLeft: 0, paddingBottom: 0, paddingRight: 20, width: 0, height: 0)
}
override func viewDidLayoutSubviews() {
scrollView.isScrollEnabled = true
// Do any additional setup after loading the view
scrollView.contentSize = CGSize(width: view.frame.width, height: 200)
}
You need to make sure that the width of the scroll view contentSize is greater than the width of the scroll view itself. Something as simple as the following should cause horizontal scrolling to happen:
override func viewDidLayoutSubviews() {
scrollView.isScrollEnabled = true
// Do any additional setup after loading the view
scrollView.contentSize = CGSize(width: view.frame.width * 2, height: 200)
}

How to mask a View with many sub views in Swift?

Masks in Swift have caused me to pull out all my hair, I'm now in the #baldclub.
I have a menu view that contains many sub views which also have many subviews. I need to mask the entire menu view so that the menu view can be animated to slide out under a button.
I have tried to simplify the problem with one container view and one subview and still have not been able to mask the views! Perhaps masks are afraid of auto-layout?
Here are the views:
let curtainMask: UIView = {
let view = UIView()
view.backgroundColor = .green
view.isUserInteractionEnabled = false
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let curtainContainer: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let locationImage: UIImageView = {
let view = UIImageView()
//view.layer.cornerRadius = 100
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .clear
view.alpha = 1
view.image = UIImage(systemName: "mappin")?.withRenderingMode(.alwaysOriginal)
view.contentMode = .scaleAspectFit
return view
}()
Here is the code being run on the main thread:
view.addSubview(curtainContainer)
curtainContainer.backgroundColor = .lightGray
curtainContainer.anchor(top: nil, left: nil, bottom: nil, right: nil, centerX: view.centerXAnchor, centerY: view.centerYAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 300, height: 200)
curtainContainer.addSubview(locationImage)
locationImage.anchor(top: curtainContainer.topAnchor, left: curtainContainer.leftAnchor, bottom: curtainContainer.bottomAnchor, right: curtainContainer.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
view.addSubview(curtainMask)
curtainMask.backgroundColor = .green
curtainMask.anchor(top: nil, left: nil, bottom: nil, right: nil, centerX: view.centerXAnchor, centerY: view.centerYAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 200, height: 100)
view.layoutSubviews()
view.setNeedsLayout()
curtainContainer.mask = curtainMask
This code crates a large gray rectangle with an image as a subview. The mask is a smaller rectangle inside the large gray rectangle. I would expect the curtainContainer view to be masked along with the image subview but the result is that nothing is drawn. Any ideas?

UIScrollView not scrolling - ambiguous content size

I am trying to create a Scroll View. The view itself is correctly
displayed but it does not scroll, even though I added a view to it and
set the content size.
NOTE: I am not using storyboards but Constraints (AutoLayout) only.
Code:
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.isScrollEnabled = true
sv.backgroundColor = .brown
return sv
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
self.view.addSubview(scrollView)
scrollView.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, bottom: self.view.bottomAnchor, right: self.view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
scrollView.contentSize = CGSize(width: self.view.frame.width, height: 2000)
print(scrollView.contentSize)
let view = UIView()
view.backgroundColor = .blue
scrollView.addSubview(view)
view.anchor(top: scrollView.topAnchor, left: scrollView.leftAnchor, bottom: scrollView.bottomAnchor, right: scrollView.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}
.anchor() is a custom extension I made in order to make constraining views easier.
Any help would be appreciated.
It's better not to mix autolayout with frame layout do
1- Comment
scrollView.contentSize = CGSize(width: self.view.frame.width, height: 2000)
2- set equal width constraint between the view inside the scrollview to the vc's view and a height constraint of 2000
For no confuse with vc's view change
let view = UIView()
to
let contentView = UIView()
then add these 2 constarints
contentView.widthAnchor.constraint(equalTo:self.view.widthAnchor).isActive = true
contentView.heightAnchor.constraint(equalToConstant:2000).isActive = true

Cannot add as subview, have to add to content view swift 4 [duplicate]

I have a function below and when I link with the iOS 11 SDK, I get an error:
Do not add subviews directly to the visual effect view itself, instead add them to the -contentView.
The problem can be solved by changing
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))"
to
effectView = UIView()
but the effect is not present that way. How can I keep using UIVisualEffectView instead of UIView? I want to keep the effect.
let imagePicker = UIImagePickerController()
let messageFrame = UIView()
var activityIndicator = UIActivityIndicatorView()
var strLabel = UILabel()
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
func activityIndicator(_ title: String) {
strLabel.removeFromSuperview()
activityIndicator.removeFromSuperview()
effectView.removeFromSuperview()
strLabel = UILabel(frame: CGRect(x: 50, y: 0, width: 160, height: 46))
strLabel.text = title
strLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.medium)
strLabel.textColor = UIColor(white: 0.9, alpha: 0.7)
effectView.frame = CGRect(x: (view.frame.midX - strLabel.frame.width/2), y: (view.frame.midY - strLabel.frame.height/2), width: 160, height: 46)
effectView.layer.cornerRadius = 15
effectView.layer.masksToBounds = true
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
activityIndicator.startAnimating()
effectView.addSubview(activityIndicator)
effectView.addSubview(strLabel)
view.addSubview(effectView)
}
Just follow what the error says and add your subviews to UIVisualEffectView's contentView.
effectView.contentView.addSubview(activityIndicator)
effectView.contentView.addSubview(strLabel)
Apple says that;
Depending on the desired effect, the effect may affect content layered
behind the view or content added to the visual effect view’s
contentView. Apply a visual effect view to an existing view and then
apply a UIBlurEffect or UIVibrancyEffect object to apply a blur or
vibrancy effect to the existing view. After you add the visual effect
view to the view hierarchy, add any subviews to the contentView
property of the visual effect view. Do not add subviews directly to
the visual effect view itself.
So, as per #the4kman add your subviews to content view of visual effect view
effectView.contentView.addSubview(activityIndicator)
effectView.contentView.addSubview(strLabel)
let messageFrame = UIView()
var activityIndicator = UIActivityIndicatorView()
var strLabel = UILabel()
effectView = UIView()
func activityIndicator(_ title: String) {
strLabel.removeFromSuperview()
activityIndicator.removeFromSuperview()
effectView.removeFromSuperview()
strLabel = UILabel(frame: CGRect(x: 50, y: 0, width: 160, height: 46))
strLabel.text = title
strLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightMedium)
strLabel.textColor = UIColor(white: 0.9, alpha: 0.7)
effectView.frame = CGRect(x: view.frame.midX - strLabel.frame.width/2, y: view.frame.midY - strLabel.frame.height/2 , width: 160, height: 46)
effectView.layer.cornerRadius = 15
effectView.layer.masksToBounds = true
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
activityIndicator.startAnimating()
effectView.addSubview(activityIndicator)
effectView.addSubview(strLabel)
view.addSubview(effectView)
}
when start :
activityIndicator("Your Text")
when Finished :
self.effectView.removeFromSuperview()

Warning from iOS "Do not add subviews directly to the visual effect view itself"

I have a function below and when I link with the iOS 11 SDK, I get an error:
Do not add subviews directly to the visual effect view itself, instead add them to the -contentView.
The problem can be solved by changing
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))"
to
effectView = UIView()
but the effect is not present that way. How can I keep using UIVisualEffectView instead of UIView? I want to keep the effect.
let imagePicker = UIImagePickerController()
let messageFrame = UIView()
var activityIndicator = UIActivityIndicatorView()
var strLabel = UILabel()
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
func activityIndicator(_ title: String) {
strLabel.removeFromSuperview()
activityIndicator.removeFromSuperview()
effectView.removeFromSuperview()
strLabel = UILabel(frame: CGRect(x: 50, y: 0, width: 160, height: 46))
strLabel.text = title
strLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.medium)
strLabel.textColor = UIColor(white: 0.9, alpha: 0.7)
effectView.frame = CGRect(x: (view.frame.midX - strLabel.frame.width/2), y: (view.frame.midY - strLabel.frame.height/2), width: 160, height: 46)
effectView.layer.cornerRadius = 15
effectView.layer.masksToBounds = true
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
activityIndicator.startAnimating()
effectView.addSubview(activityIndicator)
effectView.addSubview(strLabel)
view.addSubview(effectView)
}
Just follow what the error says and add your subviews to UIVisualEffectView's contentView.
effectView.contentView.addSubview(activityIndicator)
effectView.contentView.addSubview(strLabel)
Apple says that;
Depending on the desired effect, the effect may affect content layered
behind the view or content added to the visual effect view’s
contentView. Apply a visual effect view to an existing view and then
apply a UIBlurEffect or UIVibrancyEffect object to apply a blur or
vibrancy effect to the existing view. After you add the visual effect
view to the view hierarchy, add any subviews to the contentView
property of the visual effect view. Do not add subviews directly to
the visual effect view itself.
So, as per #the4kman add your subviews to content view of visual effect view
effectView.contentView.addSubview(activityIndicator)
effectView.contentView.addSubview(strLabel)
let messageFrame = UIView()
var activityIndicator = UIActivityIndicatorView()
var strLabel = UILabel()
effectView = UIView()
func activityIndicator(_ title: String) {
strLabel.removeFromSuperview()
activityIndicator.removeFromSuperview()
effectView.removeFromSuperview()
strLabel = UILabel(frame: CGRect(x: 50, y: 0, width: 160, height: 46))
strLabel.text = title
strLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightMedium)
strLabel.textColor = UIColor(white: 0.9, alpha: 0.7)
effectView.frame = CGRect(x: view.frame.midX - strLabel.frame.width/2, y: view.frame.midY - strLabel.frame.height/2 , width: 160, height: 46)
effectView.layer.cornerRadius = 15
effectView.layer.masksToBounds = true
activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
activityIndicator.startAnimating()
effectView.addSubview(activityIndicator)
effectView.addSubview(strLabel)
view.addSubview(effectView)
}
when start :
activityIndicator("Your Text")
when Finished :
self.effectView.removeFromSuperview()

Resources