Iphone X translation animation issue swift/xcode - swift

Only occurs in iphone X
I'm making a view appear and disappear from bottom of screen using CGAffinetransform(translationY), everything works fine in every devices but in iphone x. Two labels in a stack view as a subview of a uiview when animating labels start from 20px higher then animation starts.
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseInOut, animations: {
self.stackOrderDetailsContainer.transform = CGAffineTransform(translationX: 0, y: self.stackOrderDetailsContainer.frame.size.height)
self.blackTransparentView.transform = .identity
self.blackTransparentView.alpha = 0
self.viewArrowHolder.transform = CGAffineTransform(rotationAngle: CGFloat(-2*Double.pi))
}, completion: nil)
edit: Added code snippet

Related

Why does animated view start from wrong position?

I'm using auto layout to animate the elements in a stack view. I've set the leading and trailing constraints, both with a priority of 1000 (required). However, as you can see from the animated gif, the stack view is initially attached on the left but not on the right.
UIView.animate(withDuration: 0.125, delay: animationDelay, options: [.curveEaseOut],
animations: {
someView.transform = CGAffineTransform.identity
someView.alpha = 1
someView.isHidden = false
}, completion: nil)

Swift Animate duration not working in CGAffineTransform

When I am translating one view with an animation of 1 second it is not working, but when I am executing the transform.identity it works fine.
Here is my code:
func hideCarousel() {
UIView.animate(withDuration: 1, animations: {
self.carouselER.transform = CGAffineTransform(translationX: 0, y: 200)
})
}
func showCarousel() {
UIView.animate(withDuration: 1, animations: {
self.carouselER.transform = .identity
})
}
To solve this issue I forced the animation to run in the main thread. Every time that you have problems with the performance of your UI elements like your animations or updating your label texts, try forcing to run the UI change in the main thread.
DispatchQueue.main.async {
UIView.animate(withDuration: 1, animations: {
self.carouselER.transform = CGAffineTransform(translationX: 0, y: 200)
})
}
I have also faced that problem with one timer that updated a label, but in this issue I thought it was some kind of problem of the CGAffineTransform.

Swift contentOffset scroll

I am developing a small application for tvOS where I need to show a UITextView.
Unfortunately sometimes this text can't fit inside the screen, that's why I need a way to scroll to the bottom of it programmatically.
I've tried using the following code:
self.setContentOffset(offset, animated: true)
It's actually working as intended, except for the fact that I need to handle the animation speed, so that the user can actually read; at the moment it's too fast.
This is what I tried to do, but with little success:
let offset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
UIView.animate(withDuration: 4, animations: {
self.setContentOffset(offset, animated: false)
})
I need a way to keep the text in place and scroll it to show the missing lines.
I am using a UITextView inside an UIScrollView.
Thanks.
If anyone is looking for a solution, this is what I ended up using:
var textTopDistance = 100
//calculate height of the text not being displayed
textNotVisibleHeight = descriptionLabel.contentSize.height - scrollView.bounds.size.height
func scrollText() {
//start new thread
DispatchQueue.main.async() {
//animation
UIView.animate(withDuration: 6, delay: 2, options: UIViewAnimationOptions.curveLinear, animations: {
//set scrollView offset to move the text
self.scrollView.contentOffset.y = CGFloat(self.textNotVisibleHeight - self.textTopDistance)
}, completion: nil)
}
}
It's not perfect I know, but at least it's working as intended.

Changing UIButton alpha then doesn't recognize tap

I set up an interface very much like youtube in the sense that if a user presses on a UIView, I'll hide or show all of the subviews with an animation.
func setupControlViewVisiblity(playingVideo: Bool = false, duration: TimeInterval = 1.0, isExpanded: Bool = false){
var alpha:CGFloat = 1
if isShowingControls {
//If we're showing then we're about to hide everything so alpha is 0
alpha = 0
}
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.pausePlayButton.alpha = alpha
self.backButton.alpha = alpha
self.infoLabel.alpha = alpha
self.fullScreenButton.alpha = alpha
self.currentTimeLabel.alpha = alpha
self.videoLengthLabel.alpha = alpha
self.videoSlider.alpha = alpha
}, completion:nil)
isShowingControls = !isShowingControls
}
The issue that I'm having is that if I call this method and I show the controls (isShowingControls is true), my UIButtons will not recognize the first tap. This literally only happens when the views alpha go from 0 to 1 then I try to tap a button.
I tried doing the animation on the main queue... doesn't work. If I change the alpha from 0 to 1.... wait a few seconds... then tap the button.. it works. How can I make it work right after the UIButtons alpha changed?
Thanks
EDIT: I guess it has to do with the animation duration because when I switch it down to 0.2 it works. How can I keep it a bit higher and get this to work?
By default UIVIew animations do not allow user interaction while the animation is animating.
Luckily there is an animation option allowUserInteraction. Not much more information but you can see it in documentation here. Also worth checking out all the options here.
Try this:
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.curveEaseOut, .allowUserInteraction], animations: {
// Update the views
}, completion:nil)

Weird UIVisualEffectView behavior in multitasking

I have an AccountsViewController which has UIVisualEffectView with blur effect in background (subview at index 0), so that it covers previous controller with blur during transition. But when I then switch to another app and open multitasking menu again to switch back to my app, its blurry UIVisualEffectView seem to be damaged (as shown on the screenshot 1). When I make my app active again, the view gets "repaired" and looks ok again (as shown on the second screenshot)
Some code from my custom transitioning class where I add the blur view
// in the animateTransition.. method
guard let container = transitionContext.containerView() else {
return
}
let blurEffectView: UIVisualEffectView
if container.viewWithTag(101) != nil {
blurEffectView = container.viewWithTag(101)! as! UIVisualEffectView
}
else {
blurEffectView = UIVisualEffectView(frame: container.frame)
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
blurEffectView.tag = 101
container.addSubview(blurEffectView)
}
if self.isPresenting {
// We're presenting a view controller over another
toViewController.view.transform = CGAffineTransformMakeScale(0.7, 0.7)
container.addSubview(toViewController.view)
container.sendSubviewToBack(blurEffectView)
toViewController.view.alpha = 0
UIView.animateWithDuration(self.transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: [], animations: { () -> Void in
fromViewController.view.transform = CGAffineTransformMakeScale(0.8, 0.8)
toViewController.view.transform = CGAffineTransformMakeScale(1, 1)
blurEffectView.effect = UIBlurEffect(style: .Dark)
toViewController.view.alpha = 1
}, completion: { (completed) -> Void in
self.context?.completeTransition(completed)
})
}
else {
// We're dismissing a view controller
UIView.animateWithDuration(self.transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: [], animations: { () -> Void in
fromViewController.view.transform = CGAffineTransformMakeScale(0.7, 0.7)
toViewController.view.transform = CGAffineTransformMakeScale(1, 1)
blurEffectView.effect = nil
fromViewController.view.alpha = 0
}, completion: { (completed) -> Void in
fromViewController.view.removeFromSuperview()
self.context?.completeTransition(completed)
})
}
Seems like I've figured it out myself: this issue appears only when there is an UIWindow back (which is black) showing through.
In this question I had a transition animation container with these views:
fromViewController's view (with a scale transform 0.8;0.8)
UIVisualEffectView with .Dark style blur applied to it
toViewController's view
Because of fromViewController's view size (which was smaller than the screen because of scale transform), the black UIWindow view was showing through. And according to my research this causes UIVisualEffectView to produce a glitch described in this question.
The solution is to add a black UIView with the frame of an UIWindow and add it to the bottom of the container's view hierarchy:
let blackView = UIView(frame: container.frame)
blackView.backgroundColor = UIColor.blackColor()
container.insertSubview(blackView, atIndex: 0)
And then this glitch seem to appear no longer.