Issues when animating a simple Container View - swift

Here is the inital setup:
I have 4 constraints on the UIView...see image below.
When I go to animate it with
#IBOutlet weak var leadingCon: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
UIView.animate(withDuration: 2) {
self.leadingCon.constant = -100
self.view.layoutIfNeeded()
}
}
It slides it off to the side however...it also adjusts the bottom margin. It starts larger then needed and then animates down to the 30....not sure why.
Top Margin

Trying to perform an animation in viewDidLoad is pretty much asking for trouble. It's way too early. Your views are not even in the interface, so the user is not going to see any animation anyway. Plus, your views do not yet have any meaningful size / position! Wait until at least after viewDidLayoutSubviews so that your views can assume their initial position and size before you perform an animation. Even better, wait until viewDidAppear so that the user sees the initial position followed by the animation.

Related

UINavigationController weird transparency behaviour when presenting

I'm experiencing a weird glitch with the transparent navigation controller. When presenting a view controller with a UIImage at the top of the navigation controller: at first presents half of its background blur with a dark section, and half with a clear one; and after a very short moment it changes for a full dark background. As shown in the gif:
The UIImage displayed is mostly white, the borders are very close to pure white. So the grey color does not make much sense (less sense makes the rapid change).
I did disable extend edges under top bar in the Storyboard for the presented view controller. So the image is not hidden behind the Navigation Controller. With this option enabled the glitch does not appear, but I don't want to hide part of the image.
Disabling the transparency, solves my problem, but I'd like to be able to keep the transparency effect.
Edit: I did notice the "grey effect" also makes the navigation controller opaque. But only for that view, when going back, is transparent again.
Xcode 11, Swift 5, iOS 13.2, iPhone XS.
Thank you very much for your help.
I finally found the problem.
I didn't want the UIScrollView to bounce on top so I used this code:
extension ProblematicViewController: UIScrollViewDelegate {
/// Prevent bounce at top
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0 {
scrollView.contentOffset.y = 0
}
}
}
Which meant the ViewController's Adjust Scroll View Insets were overwrite (I think). So my scroll view did lay under the UINavigationController, to prevent this from happening, I did disable Extend Edges: Under Top Bars, so the root UIView containing the UIScrollView was not covered by the UINavigationController. So the transparency effect could never happen because the view was never under the top bar. More about Adjust Scroll View Insets on this post (helped me to find the problem).
Removing those lines and enabling Adjust Scroll View Insets and Extend Edges: Under Top Bars, solves the glitch problem, but the UIViewController does not have the "prevent bounce on top" behaviour that I wanted.
This kinda explains the weird behaviour of the UINavigationController because the SO has to calculate a transparency over nothing, but is sill strange, the transparency effect is calculated when the ProblematicViewController is fully presented, and not on viewDidLoad() or another view's life cycle before is shown to the user, so the transition is smooth, even when nothing lays behind the effect.

ARSCNView Corner Radius not showing

I have a corner radius on my ARSCNView as below;
override func viewDidLayoutSubviews() {
sceneView.layer.cornerRadius = 8
sceneView.layer.masksToBounds = true
sceneView.clipsToBounds = true
}
However, it is only showing when you enter app in background as illustrated below;
As soon as the app is in the foreground the corner radius goes back to 0.
Ive tried adding in ViewDidLoad & ViewWillAppear no success
I just tried with just
sceneView.layer.cornerRadius = 8
without masksToBounds and clipsToBounds and it worked for me.
If you're sceneView is inside another view or the root view of your view controller, check the background of that view and make sure it's something noticeable.
Maybe the sceneView itself is larger than the phones screen. Check the frame size or the layout constraints and make sure they are not causing the sceneView to stretch outside the phone screen edges.
I hope this answers your question.

Setting corner radius through viewDidAppear() or viewWillLayoutSubviews()?

In summary, setting the corner radii to get round left and right edges for my UIButtons in my application works by grabbing the buttons bounds and dividing the height by two in viewWillLayoutSubviews(). However, if I navigate to another screen via UIBarButtonItem(), rotate the device, and then navigate back to the screen with the UIButtons() they are NOT round. The corner radii are still based on the button dimensions from the previous orientaion. I tried to use viewDidAppear, but there is a second/noticable delay in setting the corner radii.
Is there anyway to speed the process up of viewDidAppear? I don't think viewWillAppear will work because the view controller isn't aware of the default (square) dimensions of the uibutton(s) I am changing.
The application I am working on is this:
Screenshots of my current application from loading screen to the point of the corner radius not being updated correctly
Use viewDidLayoutSubviews instead, because you'll have the updated bounds at that point, but not yet in viewWillLayoutSubviews.
Or I might suggesting have a button subclass that does the rounding within its own layoutSubviews, freeing your view controller from having to iterate through buttons and rounding them.
For example:
#IBDesignable
class RoundedButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
let radius = min(bounds.width, bounds.height) / 2
layer.cornerRadius = radius
}
}
And then just use this class instead of UIButton. That yields:

Display navigationbar when scrolling down

On the top of the ViewController, I have a image and I hide the navigationbar, for a better visual effect.
If the user scrolls up, there is a zoom on the image. No problem so far.
If the user scrolls down, I want to display the navigation bar with animation (very light to the correct background color of the navbar)
I ve checked here a good tutorial with the new possibilities with Ios8.
In fact, i need to perform the opposite of hidesBarsOnSwipe
So firstly, to hide the navigationbar I need to
self.navigationController?.isNavigationBarHidden = true
And after some search, I think I will need to use UIScrollViewDelegate.
But I have no idea how could i implement it .
Any hint?
What you have to do is to implement the UIScrollViewDelegate and more precisely the scrollViewDidScroll(_:) method (see documentation). This method is called each time the scroll view is scrolled.
So, in this method, you have to check that the user scrolled down and then hide the navigation bar by calling the setNavigationBarHidden(_:animated:) method of your current navigation controller (see documentation)
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let defaultOffset = view.safeAreaInsets.top
let offset = scrollView.contentOffset.y + defaultOffset
navigationController?.navigationBar.transform = .init(translationX: 0, y: min(0, -offset))
}
use this function and it scrolls up the navigation bar while scrolling up and whenever you scroll down then the navigation bar appears again..

sending UIScrollView to Background

I'm midway of finishing my app. I noticed that one of my views needs extra vertical space so I need to add a UIScrollView. Yet when I add that scroll view it overlaps everything else in the view. In simple words if I need to get it to work properly I have to delete everything off the view , add the scroll view, and then re-add everything back! Is there anyway to send this scroll view to the background of the view? This is all the code that concerns the scroll view
#IBOutlet var scrollerForPOfFourBar: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
/* non related code here*/
scrollerForPOfFourBar.userInteractionEnabled = true
scrollerForPOfFourBar.self.contentSize = CGSizeMake(320, 400)
}
I'm assuming you're using Interface Builder since you marked your scrollView as an IBOutlet.
On the view list, on the left, the order of the views specifies their Z order, with the views at the bottom being the ones drawn on top (with the largest Z).
To move your scrollView to the back, drag it just underneath of the view, and drop it there.
Keep in mind that you will have to drag all the views you had in your view into the scrollView (the easiest is to do it in the views navigator as well), and you'll have to set up any Auto Layout constraints again, which will be a pain.
Are you just want to move scrollerForPOfFourBar to back? Try this:
self.view.sendSubviewToBack(scrollerForPOfFourBar)