Cannot hide view after animation - swift

I am creating an animation which brings an image and a label from the left to the centre of the view.
imageLogo.isHidden = true is not hidden when App is run
labelLogo is not shown at all on the view
I have been reading tutorials, but I just don't see what is wrong with my code.
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool!
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off the screen here
self.imageLogo = UIImageView(image:paymentLogo)
imageLogo.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
imageLogo.center.x -= 400
self.view.addSubview(imageLogo)
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Booking Completed"
self.labelLogo.textAlignment = .center
self.view.addSubview(labelLogo)
}
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 2.0, delay: 0.1, options: [], animations: {
//animate paymentCompletedLogo
self.overlayView = UIView(frame: self.view.frame)
self.overlayView.backgroundColor = UIColor.black
self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x, y: 90, width: 200, height: 21)
self.labelLogo.backgroundColor = UIColor.gray
self.labelLogo.text = "Booking Completed"
self.labelLogo.textColor = .black
self.labelLogo.textAlignment = .center
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x,y: self.view.center.y,width: 100,height: 100)
self.view.addSubview(self.overlayView)
self.view.addSubview(self.imageLogo)
self.view.addSubview(self.labelLogo)
}) { finished in
self.overlayView.isHidden = true
self.imageLogo.isHidden = true //it is not hidden in simulator
self.logoAppeared = true
}
}

I tried removing following your code from animation method it worked fine.
You are trying to add subview in animation method. imageLogo and labelLogo is all ready added in view.
self.view.addSubview(self.overlayView)
self.view.addSubview(self.imageLogo)
self.view.addSubview(self.labelLogo)

Related

How to add activity Indicator to center of webView

With this code I get indicator but to top left corner of webView and behind borders
(I have DetailView storyboard but want to write code programmatically)
var webView = WKWebView()
var detailItem : CountriesFinal?
var spinner = UIActivityIndicatorView()
override func viewDidLoad() {
super.viewDidLoad()
spinner.frame = CGRect(x: webView.frame.width / 2, y: webView.frame.height / 2, width: 10, height: 10)
webView.addSubview(spinner)
spinner.startAnimating()
spinner.hidesWhenStopped = true
webView.backgroundColor = .blue
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
webView.frame = CGRect(x: 125, y: 150, width: 250, height: 150)
webView.layer.borderWidth = 5
webView.layer.borderColor = UIColor.red.cgColor
webView.contentMode = .scaleAspectFit
webView.backgroundColor = .blue
self.view.addSubview(webView)
I notice that this line doesn't change anything and I thought it may be the solution:
spinner.frame = CGRect(x: webView.frame.width / 2, y: webView.frame.height / 2, width: 10, height: 10)
I've tried to set translatesAutoresizingMaskIntoConstraints of spinner to false but then whole webView disappear with purple warning " Layout Issues: Position and size are ambiguous for WKWebView."
UPDATED CODE(webVIew not showing):
webView.frame = CGRect(x: 125, y: 150, width: 250, height: 150)
webView.backgroundColor = .blue
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
webView.layer.borderWidth = 5
webView.layer.borderColor = UIColor.red.cgColor
webView.contentMode = .scaleAspectFit
webView.backgroundColor = .blue
self.view.addSubview(webView)
self.view.insertSubview(spinner, aboveSubview: webView)
spinner.centerXAnchor.constraint(equalTo: webView.centerXAnchor).isActive = true
spinner.centerYAnchor.constraint(equalTo: webView.centerYAnchor).isActive = true
spinner.startAnimating()
spinner.hidesWhenStopped = true
In my opinion WKWebView is one of the system views that should probably be a "leaf" in your view hiercarchy. It is very complex in the content it manages and may not like it if you add subviews.
Instead of putting the spinner inside the WKWebView, I would probably put it into a view that is a sibling and stack it in front of the WebView in the z-order. It will float above the web view, but look like it is inside of it.
Here's a Playground I threw together that demonstrates the idea:
import UIKit
import WebKit
import PlaygroundSupport
NSSetUncaughtExceptionHandler { error in
debugPrint(error)
}
let controller = UIViewController()
let webView = WKWebView()
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
webView.load(URLRequest(url: URL(string: "https://www.apple.com")!))
let spinner = UIActivityIndicatorView()
spinner.translatesAutoresizingMaskIntoConstraints = false
controller.view.addSubview(webView)
webView.frame = controller.view.bounds
controller.view.insertSubview(spinner, aboveSubview: webView)
spinner.centerXAnchor.constraint(equalTo: webView.centerXAnchor).isActive = true
spinner.centerYAnchor.constraint(equalTo: webView.centerYAnchor).isActive = true
PlaygroundSupport.PlaygroundPage.current.liveView = controller
spinner.startAnimating()
Working code. Changed place of addSubview
webView.frame = CGRect(x: 125, y: 150, width: 250, height: 150)
webView.backgroundColor = .blue
webView.translatesAutoresizingMaskIntoConstraints = false
webView.layer.borderWidth = 5
webView.layer.borderColor = UIColor.red.cgColor
webView.contentMode = .scaleAspectFit
webView.backgroundColor = .blue
self.view.addSubview(webView)
self.webView.addSubview(self.spinner)//first we need to add subview then make center or something
spinner.center = CGPoint(x: webView.bounds.width / 2, y: webView.bounds.height / 2)
webView.navigationDelegate = self
spinner.startAnimating()
spinner.hidesWhenStopped = true

Animation of pageControl in viewController from nowhere

In my viewController which is the delegate of my scrollView
override func viewWillAppear(_ animated: Bool) {
slides = loadSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubview(toFront: pageControl)
textField.becomeFirstResponder()
}
func loadSlides() -> [Slide] {
let slide1: Slide = Bundle.main.loadNibNamed("Slide", owner: self, options: nil)?.first as! Slide
slide1.quizLabel.text = "This is slide1"
slide1.hintLabel.text = "yeah"
let slide2: Slide = Bundle.main.loadNibNamed("Slide", owner: self, options: nil)?.first as! Slide
slide2.quizLabel.text = "This is slide2"
slide2.hintLabel.text = "YEAH"
let slides = [slide1, slide2]
return slides
}
func setupSlideScrollView(slides : [Slide]) {
let width = view.frame.width
let height = view.frame.height
scrollView.frame = CGRect(x: 0,
y: 0,
width: width,
height: height)
scrollView.contentSize = CGSize(width: CGFloat(slides.count) * width, height: height)
scrollView.isPagingEnabled = true
for slide in slides {
slide.quizLabel.textColor = UIColor.white
slide.quizLabel.font = UIFont(name: (textField.font?.fontName)!, size: 20)
slide.hintLabel.textColor = UIColor.lightGray
slide.hintLabel.font = UIFont(name: (textField.font?.fontName)!, size: 18)
slide.frame = CGRect(x: CGFloat(slides.index(of: slide)!) * width,
y: 0,
width: width,
height: height)
scrollView.addSubview(slide)
}
}
When running, the pageControl shows up with a sliding animation. It seems it slides from the origin of the view. I have no idea why it comes out like that.
The pageControl is at the top
My segue settings as followed
p.s. Also, anyway to solve the similar problem for the sliding labels and the cursor?
I would like to appreciate your help in advance!

Subview Not Removing after Several "Remove View" Methods

I have this nice function that adds an activity indicator view, with a regular view behind it. When I add it, it adds fine. The problem is, when I try to remove it, nothing happens. I've tried:
.removeFromSuperview,
.isHidden = true and putting these methods in the main queue:
DispatchQueue.main.async() {
alertView.alpha = 0
alertView.removeFromSuperview()
activityIndicator.removeFromSuperview()
alertView.isHidden = true
activityIndicator.isHidden = true
}
I don't know what other methods to try...It seems all the other questions like this have one of the methods that I have as a solution. The function uses a boolean to determine whether or not to stop the activityIndicator. Here is my code:
static func showLoadingView(inViewController: UIViewController, turning: Bool){
let activityIndicator = UIActivityIndicatorView()
let alertView = UIView(frame: CGRect(x: activityIndicator.frame.origin.x, y: activityIndicator.frame.origin.y , width: 35, height: 35))
if(turning){
alertView.backgroundColor = UIColor(displayP3Red: 230, green: 230, blue: 230, alpha: 0.8)
alertView.layer.cornerRadius = 5
activityIndicator.center = alertView.center
inViewController.view.addSubview(alertView)
activityIndicator.activityIndicatorViewStyle = .gray
activityIndicator.startAnimating()
alertView.alpha = 0
activityIndicator.backgroundColor = UIColor.lightGray
alertView.center = inViewController.view.center
alertView.addSubview(activityIndicator)
alertView.transform = CGAffineTransform.init(scaleX: 1.3,y: 1.3)
UIView.animate(withDuration: 0.4) {
alertView.alpha = 1
alertView.transform = CGAffineTransform.identity
}
}
///////
else {
activityIndicator.stopAnimating()
alertView.transform = CGAffineTransform.init(scaleX: 1.3, y:1.3)
DispatchQueue.main.async() {
alertView.alpha = 0
alertView.removeFromSuperview()
activityIndicator.removeFromSuperview()
alertView.isHidden = true
activityIndicator.isHidden = true
}
print("Done")
}
}
You declared alertView which is out of scope when you called false.As a result, your call could not identify the alertView instance.
You can solve this issue in tow ways:
Declare your alertView outside of the function as a static.
static let activityIndicator = UIActivityIndicatorView()
static let alertView = UIView(frame: CGRect(x: activityIndicator.frame.origin.x, y: activityIndicator.frame.origin.y , width: 35, height: 35))
static func showLoadingView(inViewController: UIViewController, turning: Bool){}
In false case: find the subview using restorationIdentifier and remove.
static func showLoadingView(inViewController: UIViewController, turning: Bool){
if(turning){
let activityIndicator = UIActivityIndicatorView()
let alertView = UIView(frame: CGRect(x: activityIndicator.frame.origin.x, y: activityIndicator.frame.origin.y , width: 35, height: 35))
alertView.restorationIdentifier = "myalert"
alertView.backgroundColor = UIColor(displayP3Red: 230, green: 230, blue: 230, alpha: 0.8)
alertView.layer.cornerRadius = 5
activityIndicator.center = alertView.center
inViewController.view.addSubview(alertView)
activityIndicator.activityIndicatorViewStyle = .gray
activityIndicator.startAnimating()
alertView.alpha = 0
activityIndicator.backgroundColor = UIColor.lightGray
alertView.center = inViewController.view.center
alertView.addSubview(activityIndicator)
alertView.transform = CGAffineTransform.init(scaleX: 1.3,y: 1.3)
UIView.animate(withDuration: 0.4) {
alertView.alpha = 1
alertView.transform = CGAffineTransform.identity
}
}
///////
else {
for view in inViewController.view.subviews {
if (view.restorationIdentifier == "myalert") {
print("I FIND IT");
(view as! UIView).removeFromSuperview();
}
}
}
}

Swift: Setting progress of NSProgressIndicator

I have tried to setup my own NSProgressIndicator with the following method.
class ProgressViewController : NSViewController
{
override func loadView()
{
let view = NSView(frame: NSMakeRect(0,0,300,120))
view.wantsLayer = true
view.layer?.borderWidth = 0
self.view = view
let text = NSTextField(frame: NSRect(x: 20, y: 45, width: 260, height: 20))
text.drawsBackground = true
text.isBordered = false
text.backgroundColor = NSColor.controlColor
text.isEditable = false
self.view.addSubview(text)
text.stringValue = "Progress Text"
let indicator = NSProgressIndicator(frame: NSRect(x: 20, y: 20, width: 260, height: 20))
indicator.minValue = 0.0
indicator.maxValue = 100.0
indicator.doubleValue = 33.0
self.view.addSubview(indicator)
}
}
My problem is that the indicator is always shown full. Am I missing a trick?
The default style is indeterminate. Set it to false and everything should be OK:
indicator.isIndeterminate = false

UIView is not hidden when condition is met in if else statement

I am trying to create an animation and hide it 5 seconds after the task has been completed.
For some reason overlayView is not hidden off the screen when counter == 5.
var counter = 0
var timer = Timer()
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool? = false
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off screen
animateDidLayout()
}
override func viewDidAppear(_ animated: Bool) {
//move picture on screen and adjust view
animateDidAppear()
}
//called by timer every 1 seconds
func startCounting() {
if counter == 5 {
self.timer.invalidate()
self.overlayView.isHidden = true //it is not hidden
self.imageLogo.isHidden = true
self.labelLogo.isHidden = true
self.logoAppeared = true
print("counter in if \(counter)")
} else {
counter += 1
print("counter in else \(counter)")
}
}
//animate the image before it appears on screen
func animateDidLayout(){
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidLayoutSubviews, in else")
return
}
print("appeared value after else in ViewDidLayoutSubvies \(appeared)")
//animate overlayView
self.overlayView = UIView(frame: self.view.frame)
self.overlayView.backgroundColor = UIColor.black
self.overlayView.alpha = 0.4
self.view.addSubview(self.overlayView)
//animate imageLogo
self.imageLogo = UIImageView(image:paymentLogo)
imageLogo.frame = CGRect(x: 0, y: 0, width: 100,
height: 100)
imageLogo.center.x -= 400
self.view.addSubview(imageLogo)
//animate labelLogo
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textAlignment = .center
self.view.addSubview(labelLogo)
}//end of animateDidLayout
//animate the logo when the view has appeared
//call it in ViewDidAppear
func animateDidAppear() {
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidAppear, in else")
return
}
print("appeared value in viewDidAppear after else \(appeared)")
UIView.animate(withDuration: 1.0, delay: 0.1, options: [],
animations: {
//animate overlayView
// self.overlayView = UIView(frame: self.view.frame)
//self.overlayView.backgroundColor = UIColor.black
//self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x - 100,
y: 340, width: 200, height: 21)
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textColor = .white
self.labelLogo.textAlignment = .center
self.labelLogo.sizeToFit()
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x - 50,y: 250,width: 100,height: 90)
}) { finished in
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self,
selector: #selector(ThirteenthViewController.startCounting), userInfo: nil,
repeats: true)
}
} //end of animateDidAppear
I would either use a delay or use another animation with a delay to remove hide the views. I would not rely on the timer. Example with animation to remove using your code and removing the timer.
class ViewController: UIViewController {
var counter = 0
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool? = false
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off screen
animateDidLayout()
}
override func viewDidAppear(_ animated: Bool) {
//move picture on screen and adjust view
animateDidAppear()
}
//animate the image before it appears on screen
func animateDidLayout(){
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidLayoutSubviews, in else")
return
}
print("appeared value after else in ViewDidLayoutSubvies \(appeared)")
//animate overlayView
if self.view.subviews.contains(overlayView) != true{
self.overlayView = UIView(frame: self.view.frame)
self.view.addSubview(self.overlayView)
}
self.overlayView.backgroundColor = UIColor.black
self.overlayView.layer.opacity = 0.4
self.overlayView.alpha = 0.4
//animate imageLogo
if self.view.subviews.contains(imageLogo) != true{
self.imageLogo = UIImageView(image:paymentLogo)
self.view.addSubview(imageLogo)
}
imageLogo.frame = CGRect(x: 0, y: 0, width: 100,
height: 100)
imageLogo.center.x -= 400
//animate labelLogo
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textAlignment = .center
if self.view.subviews.contains(labelLogo) != true{
self.view.addSubview(labelLogo)
}
}//end of animateDidLayout
//animate the logo when the view has appeared
//call it in ViewDidAppear
func animateDidAppear() {
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidAppear, in else")
return
}
print("appeared value in viewDidAppear after else \(appeared)")
UIView.animate(withDuration: 1.0, delay: 0.1, options: [],
animations: {
//animate overlayView
// self.overlayView = UIView(frame: self.view.frame)
//self.overlayView.backgroundColor = UIColor.black
//self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x - 100,
y: 340, width: 200, height: 21)
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textColor = .white
self.labelLogo.textAlignment = .center
self.labelLogo.sizeToFit()
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x - 50,y: 250,width: 100,height: 90)
}) { finished in
}
UIView.animate(withDuration: 0.5, delay: 5.0, options: .curveEaseInOut, animations: {
self.overlayView.alpha = 0
self.imageLogo.alpha = 0
self.labelLogo.alpha = 0
}, completion: {
finished in
self.overlayView.isHidden = true //it is hidden :)
self.imageLogo.isHidden = true
self.labelLogo.isHidden = true
self.logoAppeared = true
})
} //end of animateDidAppear}
If you prefer to wait 5 seconds and hide without animation you could use
let when = DispatchTime.now() + 5
DispatchQueue.main.asyncAfter(deadline: when) {// Your code with delay}
Or as a really fun alternative using your code and the delay
class ViewController: UIViewController {
var counter = 0
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool? = false
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off screen
animateDidLayout()
}
override func viewDidAppear(_ animated: Bool) {
//move picture on screen and adjust view
animateDidAppear()
}
//animate the image before it appears on screen
func animateDidLayout(){
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidLayoutSubviews, in else")
return
}
print("appeared value after else in ViewDidLayoutSubvies \(appeared)")
//animate overlayView
if self.view.subviews.contains(overlayView) != true{
self.overlayView = UIView(frame: self.view.frame)
self.view.addSubview(self.overlayView)
}
self.overlayView.backgroundColor = UIColor.black
self.overlayView.layer.opacity = 0.4
self.overlayView.alpha = 0.4
//animate imageLogo
if self.view.subviews.contains(imageLogo) != true{
self.imageLogo = UIImageView(image:paymentLogo)
self.view.addSubview(imageLogo)
}
imageLogo.frame = CGRect(x: 0, y: 0, width: 100,
height: 100)
imageLogo.center.x -= 400
//animate labelLogo
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textAlignment = .center
if self.view.subviews.contains(labelLogo) != true{
self.view.addSubview(labelLogo)
}
}//end of animateDidLayout
//animate the logo when the view has appeared
//call it in ViewDidAppear
func animateDidAppear() {
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidAppear, in else")
return
}
print("appeared value in viewDidAppear after else \(appeared)")
UIView.animate(withDuration: 1.0, delay: 0.1, options: [],
animations: {
//animate overlayView
// self.overlayView = UIView(frame: self.view.frame)
//self.overlayView.backgroundColor = UIColor.black
//self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x - 100,
y: 340, width: 200, height: 21)
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textColor = .white
self.labelLogo.textAlignment = .center
self.labelLogo.sizeToFit()
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x - 50,y: 250,width: 100,height: 90)
}) { finished in
}
let when = DispatchTime.now() + 5
DispatchQueue.main.asyncAfter(deadline: when) {
let transition = CATransition()
transition.duration = 0.5
transition.type = "suckEffect"
self.view.layer.add(transition, forKey: nil)
self.overlayView.isHidden = true //it is hidden :)
self.imageLogo.isHidden = true
self.labelLogo.isHidden = true
self.logoAppeared = true
}
} //end of animateDidAppear}