After custom segue finishes camera turns off? - ios

I am trying to use a custom transition to a full screen custom camera. When I do so using a slow fade animation it after completing the animation turns black.
The camera which at the beginning of the animation seems to work,
suddenly goes away leaving behind the black background.
How can I make the transition work correctly?
Code:
mainVC:
#objc func buttonUp(_ sender: UIButton) {
toCam.transform = CGAffineTransform.identity.scaledBy(x: 1, y: 1)
toCam.backgroundColor = .yellow
segue()
}
func segue() {
performSegue(withIdentifier: "GoToCam", sender: self)
}
Custom segue class:
class goToCamAnimCustom: UIStoryboardSegue {
override func perform() {
scale()
}
func scale() {
guard let destinationView = self.destination.view else {
// Fallback to no fading
self.source.present(self.destination, animated: false, completion: nil)
return
}
destinationView.alpha = 0
self.source.view?.addSubview(destinationView)
UIView.animate(withDuration: CATransaction.animationDuration(), animations: {
destinationView.alpha = 0.5
}, completion: { _ in
self.source.present(self.destination, animated: false, completion: nil)
})
}
}

Related

I want to call my function from another ViewController

I have a scrollView and there is a textView inside it and there is a function that slide my scrollView(with animation) in my main vc also I have a button(inside the black circle) ,when I press it, my pop up viewcontroller opens then I choose a value for animation delay in my function.
When I press my play button (inside the red circle) , I want to dismiss my pop up vc and I want my function to run. See:
func startScrollSlideShow(sliderValue: Float) {
if (scrollView.contentOffset.y <= (scrollView.contentSize.height - scrollView.frame.size.height)){
//reach bottom
UIScrollView.animate(withDuration: TimeInterval(sliderValue), delay: 0.5, options: .allowAnimatedContent, animations: {
self.scrollView.contentOffset.y += 3.5
}) { (completion) in
self.startScrollSlideShow(sliderValue: Float(UserDefaults.standard.string(forKey: "sliderValue")!)!)
}
} else {
return
}
}
#objc func scrollTextView(){
self.present(SliderViewController(title: "Otomatik Kaydırma"), animated: true, completion: nil)
// self.startScrollSlideShow(sliderValue: Float(UserDefaults.standard.string(forKey: "sliderValue")!)!)
}
these are in my main vc not my pop up vc.
You can use the delegate pattern for this:
protocol PlayViewDelegate: class {
func playButtonPressed()
}
// Implement the protocol in your Main VC
extension MainViewController: PlayViewDelegate {
func playButtonPressed() {
// Play
}
}
// Add delegate to the alert like VC
class PlayViewController: UIViewController {
weak var delegate: PlayViewDelegate?
#IBAction
func playPressed() {
self.delegate?.playButtonPressed()
self.dismiss(animated: true, completion: nil)
}
}

withDuration is ignored during UIView.animate

I'am trying to animate the opacity of a AVPlayerLayer when a button is tapped. Here is my function :
#IBAction func boutonTapped(_ sender: UIButton) {
if(paused){
UIView.animate(withDuration: 5.0, animations: {
self.avPlayerLayer.opacity = 1.0
}, completion: nil)
//avPlayer.play()
}else{
UIView.animate(withDuration: 5.0, animations: {
self.avPlayerLayer.opacity = 0
}, completion:nil)
//avPlayer.pause()
}
paused = !paused
}
An opacity animation is launched but it is very speed (about 0.5s). I tried to change the duration for 10s and the animation is the same
I tried to add self.view.layoutIfNeeded() inside the animation block with no effect.
Have you any idea ? Thanks !
Instead of animating the opacity of avPlayerLayer, try animating the alpha of the customView where you're adding avPlayerLayer, i.e.
#IBAction func boutonTapped(_ sender: UIButton) {
UIView.animate(withDuration: 5.0) {
self.customView.alpha = paused ? 1.0 : 0.0 //here...
paused ? self.avPlayer.play() : self.avPlayer.pause()
}
paused = !paused
}
There is no need to call self.view.layoutIfNeeded().
You should change an animation code to change opacity of AVPlayerLayer as follow:
#IBAction func boutonTapped(_ sender: UIButton) {
UIView.transition(with: self.videoPlayerView, duration: 5.0, options: [.transitionCrossDissolve], animations: {
self.videoPlayerView.layer.sublayers?.first(where: { $0 is AVPlayerLayer })?.opacity = paused ? 1 : 0
}, completion: nil)
paused ? avPlayer.play() : avPlayer.pause()
}
videoPlayerView is view where you have added AVPlayerLayer instance.
I think you need to put self.view.layoutIfNeeded() inside animation block but not the opacity update code. Like this,
#IBAction func boutonTapped(_ sender: UIButton) {
if (paused) {
self.avPlayerLayer.opacity = 1.0
//avPlayer.play()
} else {
self.avPlayerLayer.opacity = 0
//avPlayer.pause()
}
UIView.animate(withDuration: 5.0, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
paused = !paused
}

UIPageViewController transition bugged if animation starts in the meanwhile

I have a strange behaviour in my app using a UIPageViewController.
The layout of my app is a PageViewController (camera roll like) with a ads banner on bottom.
The banner's container starts as hidden and, when the ad gets loaded, i set the isHidden=false with an animation.
My problem is that when the banner gets into the screen it breaks the UIPageViewController transition if in progress as shown in this video:
I made a new project that reproduces the error very easy with a few lines, you can checkout it in GITHUB: You just need to spam the "Next" button until the banner gets loaded. It also can be reproduced by swipping the PageViewController but is harder to reproduce.
The full example code is:
class TestViewController: UIViewController,UIPageViewControllerDelegate,UIPageViewControllerDataSource {
#IBOutlet weak var constraintAdviewHeight: NSLayoutConstraint!
weak var pageViewController : UIPageViewController?
#IBOutlet weak var containerAdView: UIView!
#IBOutlet weak var adView: UIView!
#IBOutlet weak var containerPager: UIView!
var currentIndex = 0;
var clickEnabled = true
override func viewDidLoad() {
super.viewDidLoad()
let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
pageViewController = pageVC
pageVC.delegate = self
pageVC.dataSource = self
addChildViewController(pageVC)
pageVC.didMove(toParentViewController: self)
containerPager.addSubview(pageVC.view)
pageVC.view.translatesAutoresizingMaskIntoConstraints = true
pageVC.view.frame = containerPager.bounds
pushViewControllerForCurrentIndex()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.containerAdView.isHidden = true
DispatchQueue.main.asyncAfter(deadline: .now()+4) {
self.simulateBannerLoad()
}
}
#IBAction func buttonClicked(_ sender: Any) {
guard clickEnabled else {return}
currentIndex -= 1;
pushViewControllerForCurrentIndex()
}
#IBAction func button2Clicked(_ sender: Any) {
guard clickEnabled else {return}
currentIndex += 1;
pushViewControllerForCurrentIndex()
}
private func simulateBannerLoad(){
constraintAdviewHeight.constant = 50
pageViewController?.view.setNeedsLayout()
UIView.animate(withDuration: 0.3,
delay: 0, options: .allowUserInteraction, animations: {
self.containerAdView.isHidden = false
self.view.layoutIfNeeded()
self.pageViewController?.view.layoutIfNeeded()
})
}
//MARK: data source
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
return getViewControllerForIndex(currentIndex+1)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
return getViewControllerForIndex(currentIndex-1)
}
func getViewControllerForIndex(_ index:Int) -> UIViewController? {
guard (index>=0) else {return nil}
let vc :UIViewController = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: "pageTest")
vc.view.backgroundColor = (index % 2 == 0) ? .red : .green
return vc
}
func pushViewControllerForCurrentIndex() {
guard let vc = getViewControllerForIndex(currentIndex) else {return}
print("settingViewControllers start")
clickEnabled = false
pageViewController?.setViewControllers([vc], direction: .forward, animated: true, completion: { finished in
print("setViewControllers finished")
self.clickEnabled = true
})
}
}
Note: Another unwanted effect is that the last completion block when the bug occurs does not get called, so it leaves the buttons disabled:
func pushViewControllerForCurrentIndex() {
guard let vc = getViewControllerForIndex(currentIndex) else {return}
print("settingViewControllers start")
clickEnabled = false
pageViewController?.setViewControllers([vc], direction: .forward, animated: true, completion: { finished in
print("setViewControllers finished")
self.clickEnabled = true
})
}
Note2: The banner load event is something I can't control manually. Due to the library used for displaying ads its a callback in the main thread that can happen in any moment. In the sample proyect this is simulated with a DispatchQueue.main.asyncAfter: call
How can I fix that? Thanks
What wrong?
Layout will interrupt animation.
How to prevent?
Not change layout when pageViewController animating.
When the ad is loaded:
Confirm whether pageViewController is animating, if so, wait until the animation is completed and then update, or update
Sample:
private func simulateBannerLoad(){
if clickEnabled {
self.constraintAdviewHeight.constant = 50
} else {
needUpdateConstraint = true
}
}
var needUpdateConstraint = false
var clickEnabled = true {
didSet {
if clickEnabled && needUpdateConstraint {
self.constraintAdviewHeight.constant = 50
needUpdateConstraint = false
}
}
}
For us, it was due to a device rotation causing a layout pass at the same time as an animation to a new view controller. We could not figure out how to stop the layout pass in this situation.
This worked for us:
let pageController = UIPageViewController()
func updatePageController() {
pageController.setViewControllers(newViewControllers, direction: .forward, animated: true, completion: {[weak self] _ in
// There is a bug with UIPageViewController where a layout pass during an animation
// to a new view controller can cause the UIPageViewController to display the old and new view controller
// In our case, we can compare the view controller `children` count against the the `viewControllers` count
// In other cases, we may need to examine `children` more closely against `viewControllers` to see if there discrepancies.
// Since this is on the animation callback we need to dispatch to the main thread to work around another bug: https://stackoverflow.com/a/24749239/2191796
DispatchQueue.main.async { [weak self] in
guard let self = self else {return}
if self.pageController.children.count != self.pageController.viewControllers?.count {
self.pageController.setViewControllers(self.pageController.viewControllers, direction: .forward, animated: false, completion: nil)
}
}
})
}

Animated display button

I'm trying to create a basic animation. I need to touch on a button to hide or show.
I wrote this code to tap on the screen:
func visibleControlButton(_ sender: UITapGestureRecognizer) {
if (backButton!.isHidden) {
_UIButtonHiddenAnimation.hiddenAnimation(button: self.backButton!, hide: false)
} else {
_UIButtonHiddenAnimation.hiddenAnimation(button: self.backButton!, hide: true)
}
}
Definition _UIButtonHiddenAnimation:
class _UIButtonHiddenAnimation {
class func hiddenAnimation(button: UIButton, hide: Bool) {
UIView.animate(withDuration: 0.2,
animations: {
hide ? (button.alpha = 0) : (button.alpha = 1.0)
},
completion: {
finished in hide ? (button.isHidden = true) : (button.isHidden = false)
})
}
}
Animates just hide the button. How to make an animated appearance of a button?
The problem is that if the button is hidden, you are animating the alpha to 1 but we cannot see that — because the button is hidden! Then you set isHidden to false and the button jumps into view.
The solution: forget all about isHidden and change only the alpha — and then change your if test to match what you are doing with the button, i.e. simply test against its alpha value. Thus (neatening things up as we go):
class _UIButtonHiddenAnimation {
class func hiddenAnimation(button: UIButton, hide: Bool) {
UIView.animate(withDuration: 0.2, animations: {
button.alpha = hide ? 0 : 1.0
})
}
}
func visibleControlButton(_ sender: UITapGestureRecognizer) {
_UIButtonHiddenAnimation.hiddenAnimation(
button: self.backButton!, hide: backButton!.alpha > 0.1)
}

UIView is not aminating for the first time

I am trying to animate a UIView on button click.
It does appear on first click but only after that.
#IBAction func viewDetails(sender: AnyObject) {
UIView.animateWithDuration(0.5 as NSTimeInterval, animations: {
println(self.viewDetailsView.center.x)
println(self.viewDetailsView.hidden)
self.viewDetailsView.hidden = false
self.viewDetailsView.center = CGPointMake(self.viewDetailsView.center.x - 4000, self.viewDetailsView.center.y)
self.view.layoutIfNeeded()
}, completion: {
finished in
self.detailsVisible = true
}) }
Trying this:
#IBAction func viewDetails(sender: AnyObject) {
println(self.viewDetailsView.center.x)
println(self.viewDetailsView.hidden)
self.viewDetailsView.hidden = false
self.viewDetailsView.center = CGPointMake(self.viewDetailsView.center.x - 4000, self.viewDetailsView.center.y)
UIView.animateWithDuration(0.5 as NSTimeInterval, animations: {
self.view.layoutIfNeeded()
}, completion: { finished in
self.detailsVisible = true
})
}

Resources