NVActivityIndicatorView not working on button press - ios

I have the following code for a button in my application to test my implementation of NVActivityIndicatorView:
#IBAction func goButtonPressed(_ sender: Any) {
self.startAnimatingActivityIndicator()
sleep(2)
self.stopAnimatingActivityIndicator()
}
The view controllers in my application also have this extension:
extension UIViewController: NVActivityIndicatorViewable {
func startAnimatingActivityIndicator() {
let width = self.view.bounds.width / 3
let height = width
let size = CGSize(width: width, height: height)
startAnimating(size, message: "Loading...", type: NVActivityIndicatorType.circleStrokeSpin)
}
func stopAnimatingActivityIndicator() {
self.stopAnimating()
}
}
The loading animations work elsewhere in the same view controller (i.e., the viewDidLoad() function) but for some reason I'm unable to get the loading animation to work on this button. The button is connected correctly as the application does sleep for the appropriate amount of time, but the loading animations fail to run.
Thanks in advance for the help!

The Indicator won't spin because the main thread is asleep. Use a 2 second timer to turn off the spinning instead.

#FryAnEgg coming in with the solution! The sleep(2) was preventing the loading animations from running.
Here's my updated code:
#IBAction func goButtonPressed(_ sender: Any) {
self.startAnimatingActivityIndicator()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.stopAnimatingActivityIndicator()
}
}

Related

When using scrollView.zoom I get different results from pressing a button to calling a function

I am trying to zoom to a button on a UIScrollView. The first function is one that I run if I segue to the vc, the second is run from a button in the view.
When running the second function it goes perfectly and centres correctly
On the first however, despite being identical code, it has an offset in the x of about 40-50 pixels (Shows a point left of the button, not any part of it) although this offset changes dependent on the button.
func moveScrollviewToRoom(){
scrollView.zoom(to: artButton.frame, animated: true)
}
#IBAction func moveScrollview(_ sender: Any) {
scrollView.zoom(to: artButton.frame, animated: true)
}
The function was called here:
override func viewDidLoad() {
super.viewDidLoad()
if moveToRoom != "" {
moveScrollviewToRoom()
}
Any help would be greatly appreciated
Cheers!
Two points...
1 - Views and subviews have not yet been positioned by auto-layout in viewDidLoad(), so the artButton.frame will not be correct.
2 - Calling any function that animates a view from viewDidLoad() won't give the desired results, because the view is not even visible yet.
Move your call to viewDidAppear():
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if moveToRoom != "" {
moveScrollviewToRoom()
}
}

Auto resizing corner radius using viewDidLayoutSubviews() not updating the view before it is displayed

I'm new to swift and Xcode so there may be a simple answer or better way to do this. I am trying to make rounded edges to my buttons in all size iOS devices and the best way that I have found so far is using this method:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for i in 0..<buttons.count {
self.buttons[i].layer.cornerRadius = self.buttons[i].bounds.size.height / 2
}
examResultsBackButtonOutlet.layer.cornerRadius = examResultsBackButtonOutlet.bounds.size.height / 2
}
// Build UI
func loadUI() {
// Round the edges, change color background, font
titleOutlet.mainMenuStyle("", 75, earthGreenWithAlpha)
for i in 0..<buttons.count {
buttons[i].mainMenuStyle("", 40)
}
print("Main Menu successful load")
}
I call the loadUI() method in my viewDidLoad method for what its worth:
//MARK: viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
// Load the UI
loadUI()
loadExamResultsView()
mainMenu()
examResultsStackView.isHidden = true
loadStoredScores()
loadStoredSettings()
}
The issue presents itself not when I start the app for the first time (this is the first scene/View Controller), rather the issue occurs when I segue back to this scene from my second View Controller.
What happens is the buttons are formatted weird for about a half a second, then they are reformatted perfectly:
Correctly formatted screenshot
Incorrectly formatted screenshot
You'll notice the second image (which only occurs for about 0.5 seconds) has much more intense corner radius'.
How can I prevent this from happening so that the user only sees the perfectly round corner radius' for each button and not the poor janky ones?
Thanks!
Thanks for everyone's feedback but here is what fixed it for me:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
for i in 0..<buttons.count {
self.buttons[i].layer.cornerRadius = self.buttons[i].bounds.size.height / 2
}
examResultsBackButtonOutlet.layer.cornerRadius = examResultsBackButtonOutlet.bounds.size.height / 2
}
This replaced the original post:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for i in 0..<buttons.count {
self.buttons[i].layer.cornerRadius = self.buttons[i].bounds.size.height / 2
}
examResultsBackButtonOutlet.layer.cornerRadius = examResultsBackButtonOutlet.bounds.size.height / 2 }
Thanks!
Maybe you can try this:
https://imgur.com/a9kTt98
or add to extension of UIView
extension UIView {
#IBInspectable var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = (newValue > 0)
}
}
}

How do I make subview appear in UI immediately after adding it?

Essentially I want a label to appear as a subview when I add it and not wait until the current thread has finished what it is doing. In the below example, the label appears in the UI of the app at the same time 'Awake' is printed. Do you know how I can get the subview to appear in the UI before the thread sleeps?
#IBAction func ButtonTapped(_ sender: Any) {
let label = UILabel(frame: self.view.bounds)
label.text = "Label Text"
self.view.addSubview(label) // I want this to appear on the UI before...
sleep(3)
print("Awake") // ... this is printed
}
And enclosing the addSubView() line within DispatchQueue.main.async {} doesn't fix the issue.
Thanks.
Thanks to Paulw11, I figured out that I need to do the processing on a background thread. Simple solution in swift:
#IBAction func ButtonTapped(_ sender: Any) {
let label = UILabel(frame: self.view.bounds)
label.text = "Label Text"
self.view.addSubview(label) // I want this to appear on the UI before...
DispatchQueue.global(qos: .background).async {
sleep(3)
print("Awake") // ... this is printed
}
}

Swift animations in a new view happen instantly

One my primary view, animations execute according to the delay and durations set. However, when I segue to a new view, the animations are all complete instantly. How is this? This only happens when this animations told to execute from code in the viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
setProgress()
}
// the function below annimates a circular progress view
func setProgress() {
var to:Double = ((360.0 / 4) * increment)
progressCircle.animateFromAngle(360.0, toAngle: to, duration: 5) { completed in
if completed {
print("animation stopped, completed")
} else {
print("animation stopped, was interrupted")
}
}
}
viewDidLoad occurs before the view is presented on screen, if you want to run animations you should probably run them in viewDidAppear so that the view is loaded on screen and the components are visible.
call setProgress() in viewDiDAppear
override public func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
setProgress()
}
Maybe you can add delay and keep it running on a timer after viewdidload event of controller. Therefore you may reach your goal and run the animations in the time that you want.

UIRefreshControl not refreshing when triggered programmatically

I am trying to show a refresh control right when the view loads to show that I am getting getting data from Parse. The refresh control works as it should when the app is running, but I cannot get it to fire programmatically from anywhere in my app.
This is the code that does not appear to run:
override func viewDidAppear(animated: Bool) {
self.refresher.beginRefreshing()
}
Not only does this not run, but having the code in the app changes the attributes of the refresh control. When I have this code in the app, and show the refresher from user interaction, the refresh control does not have its attributed title as it usually does nor does it run the code that it should.
I needed to add a delay between setContentOffset and the self.refreshControl?.sendActions(for: .valueChanged) call. Without the delay, the refreshControl's attributedTitle would not render.
This works in iOS 10 (Swift 3):
self.tableView.setContentOffset(CGPoint(x:0, y:self.tableView.contentOffset.y - (self.refreshControl!.frame.size.height)), animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: {
self.refreshControl?.sendActions(for: .valueChanged)
})
Here's an extension working on 10.3:
extension UIRefreshControl {
func refreshManually() {
if let scrollView = superview as? UIScrollView {
scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - frame.height), animated: false)
}
beginRefreshing()
sendActions(for: .valueChanged)
}
}

Resources