Remove programmatically UILabel after adding - swift - ios

I have made a UIView and two UILabels programmatically. The labels say something like: "There are no posts, follow someone to add to your feed.".
self.update.count shows the number of posts to show. So if it is 0 is should show the labels that I made. If not it should not show any of the labels.
I have made this code but it wont remove the labels and the UIView again? it is inside the viewWillAppear:
if self.updates.count == 0 {
print("THERE ARE NO POSTS: \(self.updates.count)")
self.tableView.addSubview(self.noPostView)
self.tableView.addSubview(self.noPostLabel)
self.tableView.addSubview(self.noPostText)
//noPostView.anchorToTop(view.topAnchor, left: nil, bottom: view.bottomAnchor, right: nil)
self.noPostView.centerXAnchor.constraintEqualToAnchor(self.tableView.centerXAnchor).active = true
//noPostView.centerYAnchor.constraintEqualToAnchor(tableView.centerYAnchor).active = true
self.noPostView.anchor(self.view.topAnchor, left: nil, bottom: nil, right: nil, topConstant: 80, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: self.view.frame.width, heightConstant: self.noPostLabel.frame.height + self.noPostText.frame.height)
self.noPostLabel.anchor(self.view.topAnchor, left: nil, bottom: nil, right: nil, topConstant: 80, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: self.noPostView.frame.width, heightConstant: 50)
self.noPostLabel.centerXAnchor.constraintEqualToAnchor(self.noPostView.centerXAnchor).active = true
self.noPostText.anchor(self.noPostLabel.bottomAnchor, left: self.noPostView.leftAnchor, bottom: nil, right: self.noPostView.rightAnchor, topConstant: -20, leftConstant: 35, bottomConstant: 0, rightConstant: 35)
self.noPostText.heightAnchor.constraintEqualToConstant(60).active = true
self.noPostText.centerXAnchor.constraintEqualToAnchor(self.noPostView.centerXAnchor).active = true
self.loadingSpinner.stopAnimating()
} else {
print("THERE ARE: \(self.updates.count) POSTS")
self.tableView.willRemoveSubview(self.noPostView)
self.tableView.willRemoveSubview(self.noPostText)
self.tableView.willRemoveSubview(self.noPostLabel)
}

Just hide the labels when you don't need them i.e "self.noPostLabel.isHidden = true" and show them when needed.

You are using willRemoveSubview(_:) which apple describes below.
The default implementation of this method does nothing. Subclasses can
override it to perform additional actions whenever subviews are
removed. This method is called when the subview’s superview changes or
when the subview is removed from the view hierarchy completely.

Related

Adding subview to another subview using Auto Layout

I'm sure I am missing something stupid here, but I have mainView, subviewA, and subviewB. I am trying to add subviewB to subviewA and anchor it inside of subviewA, however it is not anchoring (just remains in top left corner. However, if I add subviewB to mainView and then anchor it, it works fine.
Example (using a custom anchoring function that I believe is self-explanatory):
addSubview(questionContainerView)
questionContainerView.anchor(topAnchor, left: leftAnchor, bottom: centerYAnchor, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
// does not work
questionContainerView.addSubview(questionTextLabel)
questionTextLabel.anchor(questionContainerView.topAnchor, left: questionContainerView.leftAnchor, bottom: questionContainerView.bottomAnchor, right: questionContainerView.rightAnchor, topConstant: 25, leftConstant: 10, bottomConstant: 25, rightConstant: 10, widthConstant: 0, heightConstant: 0)
// does work
addSubview(questionTextLabel)
questionTextLabel.anchor(questionContainerView.topAnchor, left: questionContainerView.leftAnchor, bottom: questionContainerView.bottomAnchor, right: questionContainerView.rightAnchor, topConstant: 25, leftConstant: 10, bottomConstant: 25, rightConstant: 10, widthConstant: 0, heightConstant: 0)
I tried the same code with different background color and found nothing wrong with it, maybe because of same background color, it wont be visible.
Please find the code below
self.view.addSubview(questionContainerView)
questionContainerView.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, bottom: self.view.centerYAnchor, right: self.view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
questionContainerView.backgroundColor = .blue
questionContainerView.addSubview(questionTextLabel)
questionTextLabel.anchor(top: questionContainerView.topAnchor, left: questionContainerView.leftAnchor, bottom: questionContainerView.bottomAnchor, right: questionContainerView.rightAnchor, topConstant: 25, leftConstant: 10, bottomConstant: 25, rightConstant: 10, widthConstant: 0, heightConstant: 0)
questionTextLabel.backgroundColor = .black
You cannot add the same view to two separate parent views. Once you add it to a different view, it will be removed from the previous view. If you want the label view on both views, simply create two instances of it.
questionContainerView.addSubview(questionTextLabel) // first time
addSubview(questionTextLabel) // second time the questionTextLabel is removed from questionContainerView

Views alpha and frame property spoil when UITextFields first responder changes

I have a view (Lets called thirdStackView) and two textfield (Lets called them textfield b and c).
In my viewdidload, I give their anchors and make textfields alpha to 0, also y frame of textfields to -100. With a button tap, I move thirdstachview out of screen with an animation and make textfields visible and make their frame +100.
My problem is that when I change textfield, thirdstackview started to seen on screen and textfields positions move back to ones I gave in viewdidload. Also when I dismiss keyboard, this problem occurs.
I guess It is something about layoutIfneeded() but What can be the problem?
override func viewDidLoad() {
thirdStackView.anchor(self.btnStackView.bottomAnchor, left: self.view.leftAnchor, bottom: self.emergenyBtn.topAnchor, right: self.view.rightAnchor, topConstant: 20, leftConstant: 20, bottomConstant: 13, rightConstant: 20, widthConstant: 0, heightConstant: 0)
self.createTextField(placeHolderText: getLabelText(key: CMSKeys.CMS_TF_TCKNID), titleText: getLabelText(key: CMSKeys.CMS_TF_TCKNID), imageName: "id-icon",leftButtons: [.backDisabled,.forward], rightButtons: [.cancel],textField: idTextField)
idTextField.tag = 1
idTextField.keyboardType = UIKeyboardType.numberPad
idTextField.anchor(self.btnStackView.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: self.view.rightAnchor, topConstant: 20, leftConstant: 30, bottomConstant: 0, rightConstant: 30, widthConstant: 0, heightConstant: 40)
idTextField.alpha = 0
self.createTextField(placeHolderText: getLabelText(key: CMSKeys.CMS_TF_PHONE), titleText: getLabelText(key: CMSKeys.CMS_TF_PHONE), imageName: "phone-icon",leftButtons: [.back,.forward], rightButtons: [.cancel],textField: phoneTextField)
phoneTextField.keyboardType = UIKeyboardType.numberPad
phoneTextField.tag = 2
phoneTextField.anchor(idTextField.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: self.view.rightAnchor, topConstant: 20, leftConstant: 30, bottomConstant: 0, rightConstant: 30, widthConstant: 0, heightConstant: 40)
phoneTextField.alpha = 0
}
My animation function;
#objc func adminBtnTapped(_ button: UIButton) {
if(btnTapped){
UIView.transition(with: button, duration: 0.5, options: .transitionCrossDissolve, animations: {
self.emergenyBtn.frame.origin.y -= 20
}, completion: nil)
UIView.animate(withDuration: 1, animations: {
self.thirdStackView.frame.origin.y += self.view.bounds.height
self.bgView.frame.origin.y += self.view.bounds.height
self.backBtn.frame.origin.x += self.view.bounds.width
self.idTextField.frame.origin.y += 100
self.idTextField.alpha = 1.0
self.phoneTextField.frame.origin.y += 100
self.phoneTextField.alpha = 1.0
self.passTextField.frame.origin.y += 100
self.passTextField.alpha = 1.0
}) { (_) in
//self.emergenyBtn.setTitle("Giriş Yap", for: UIControlState.normal)
self.view.layoutIfNeeded()
}
btnTapped = false
}
}
When I make superviews "translatesAutoresizingMaskIntoConstraints" attribute to false, It solved. I think, when It is true, auto layout constraints messed up.
self.view.translatesAutoresizingMaskIntoConstraints = false
For gurus that this answer is not enough, you can check official Apple document
https://developer.apple.com/documentation/uikit/uiview/1622572-translatesautoresizingmaskintoco
From Apple Document
Note that the autoresizing mask constraints fully specify the view’s size and position; therefore, you cannot add additional constraints to modify this size or position without introducing conflicts.

UIView wont appear

I have a function in my viewController that lays out my views using SnapKit. The funcion looks like this
#objc func setupView(){
//will add the scroll view to the subview
view.addSubview(scrollView)
scrollView.addSubview(imageContainer)
scrollView.addSubview(eventInfoVIew)
// scrollView.addSubview(currentEventImage)
scrollView.contentInsetAdjustmentBehavior = .never
scrollView.backgroundColor = .green
eventInfoVIew.backgroundColor = .red
imageContainer.backgroundColor = .blue
scrollView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
imageContainer.anchor(top: scrollView.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: view.frame.width, height: view.frame.height - 200)
eventInfoVIew.anchor(top: imageContainer.bottomAnchor, left: view.leftAnchor, bottom: scrollView.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.scrollIndicatorInsets = view.safeAreaInsets
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: view.safeAreaInsets.bottom, right: 0)
}
However when I run the app one of the views isn't there and it makes no sense because to the best of my knowledge I laid out the constraints properly. The eventInfoView is the one giving me problems.
Sorry forgot to add image of current screen
Have you try debugging with the view inspector? What happens with your views? A screenshot of the view hierarchy would help a lot.
Without this, my hunch is that you are not using enough constraints and therefore your layout is ambiguous. Don't forget that UIScrollView requires 6 constraints to layout properly instead of 4.
Edit: If you want to check if the scrollView is the issue, try adding this code inside
scrollView.snp.makeConstraints { (make) in
make.edges.equalTo(view)
make.width.height.equalTo(view)
}

UITabBar change view hierarchy after rotating process. (or changes its position in view hierarchy)

I have a view with several subviews (with only one peculiarity I added tabBar as a subview to a view of VC)
super.viewDidLoad()
view.addSubview((tabBarController?.tabBar)!)
view.addSubview(collectionView)
view.addSubview(pageControl)
view.addSubview(skipButton)
view.addSubview(nextButton)
print( view.constraints)
nextButton.anchorWithConstantsToTop(view.topAnchor, left: nil, bottom: nil, right:
view.rightAnchor, topConstant: 16, leftConstant: 0, bottomConstant: 0, rightConstant: 0)
nextButtonTopAnchor = nextButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 0)
nextButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
nextButton.widthAnchor.constraint(equalToConstant: 60).isActive = true
skipButton.anchorWithConstantsToTop(view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, topConstant: 16, leftConstant: 0, bottomConstant: 0, rightConstant: 0)
skipButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
skipButton.widthAnchor.constraint(equalToConstant: 60).isActive = true
pageControl.anchorWithConstantsToTop(nil, left: view.leftAnchor, bottom: tabBarController?.tabBar.topAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 28, bottomConstant: 0, rightConstant: 30)
pageControl.heightAnchor.constraint(equalToConstant: 121).isActive = true
collectionView.anchorToTop(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
Something bizarre (for me) happend when I rotate device.
1) in portrait orientation everything ok. All subviews stands in hierarchy chain as they are supposed to. (especially UITabBar)
but then after rotation process to landscape orientation UITabbar separates from UIView, and of course constraint regarding to pageControl bottom: tabBarController?.tabBar.topAnchor is vanished.
Why is it happens?

Add UIView behind iPhone X status bar

I have an App, that doesn't have a UINavigationController and it has a UICollectionView with some cells as its feed.
To avoid the cells appearing behind the status bar, I added a UIView behind it.
Before iPhone X it was pretty simple to do this, as the following:
let v = UIView()
v.backgroundColor = .white
view.addSubview(v)
v.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 0, paddinfLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 20)
By doing so, a tiny white layer would appear behind it as expected.
(this anchor method is from an extension, not language-default).
How can I achieve this for iPhone X ?
So far I tried the following code:
if #available(iOS 11, *) {
v.anchor(top: view.safeAreaLayoutGuide.topAnchor, left: view.safeAreaLayoutGuide.leftAnchor, bottom: nil, right: view.safeAreaLayoutGuide.rightAnchor, paddingTop: 0, paddinfLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 20)
let window = UIWindow(frame: UIScreen.main.bounds)
print("window.safeAreaInsets.top:", window.safeAreaInsets.top)
if window.safeAreaInsets.top > CGFloat(0.0) {
print("iPhone X")
v.anchor(top: view.safeAreaLayoutGuide.topAnchor, left: view.safeAreaLayoutGuide.leftAnchor, bottom: nil, right: view.safeAreaLayoutGuide.rightAnchor, paddingTop:-44, paddinfLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: window.safeAreaInsets.top)
} else {
v.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 0, paddinfLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 20)
}
}
but it doesn't work.
What's the best approach in this case?
Thank you
You have to tell your collectionView to adjust the insets:
if #available(iOS 11, *) {
collectionView.contentInsetAdjustmentBehavior = .scrollableAxes
}
This will make sure your content will be inset enough so it's not overlapped by the iPhone X's status bar.

Resources