I am showing an alertController and if the user clicks Yes an ProgressView should be shown, but unfortunately the Progressview and the label does not appear. How can I refresh my ViewController. Here the cod that is executed for the yes-handler of the alertController. The code will be executed without problem, but the progressview is not appearing:
func initProgressView(){
turn = 0
let xCoord = self.view.center.x
let yCoord = self.view.center.y + 10
progressLabel = UILabel(frame: CGRect(x: xCoord, y: yCoord, width: 100, height: 23))
progressLabel.text = "0 %"
progressLabel.font = UIFont.boldSystemFontOfSize(14)
progressView.center = self.view.center
progressView.trackTintColor = UIColor.lightGrayColor()
progressView.tintColor = UIColor.blueColor()
// self.view.backgroundColor = UIColor.yellowColor()
self.view.addSubview(progressLabel)
self.view.addSubview(progressView)
}
here the complete sequence of call:
initProgressView() //see previous post
then call of importData:
func importData (source : ImportDataInterface, data : NSData, progressStep : Int) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
source.importData(data)
dispatch_async(dispatch_get_main_queue(), {
self.counter += progressStep
return
})
})
}
and finally in the calling function:
progressView.removeFromSuperview()
progressLabel.removeFromSuperview()
How can I refresh the ViewController or what else could be the reason why the progressView does not appear. Can it be, that constraints or autolayout issues are the problem.
thanks
Arnold
You haven't provided enough information. You need to show us the sequence of calls.
iOS doesn't render changes to the screen until your code returns. The following coding pattern will not work:
create progress indicator
add progress indicator to superview
start progress indicator spinning
do long-running task
stop progress indicator
Instead, what you have to do is something like this:
create progress indicator
add progress indicator to superview
start progress indicator spinning
invoke long-running task with a call to dispatch_after and a delay of 0:
dispatch_after(main queue, delay 0)
{
do long running task
stop activity indicator
}
The call to dispatch_after queues up your closure to run on the main thread the next time your code returns and the event loop even if the delay value is 0.
looks like that progressView overlaps progressLabel, probably you need change last 2 strings order?
self.view.addSubview(progressView)
self.view.addSubview(progressLabel)
Related
I want to display my upload progress of a file in the table view cell.
I am using Progress View programatically for the same. However, the progress view overlaps the file name and its related data. How can I make the progress view appear behind the text?
Following is the code used:
let animationProgress = UIProgressView(progressViewStyle: .bar)
var prog: Float = 0.0
animationProgress.progress += 0.5
animationProgress.rightAnchor.accessibilityActivate()
animationProgress.tintColor = .dbbSearchBarBackgroundColor()
animationProgress.setProgress(prog, animated: true)
perform(#selector(updateProgress), with: nil, afterDelay: 1.0)
animationProgress.frame = CGRect(x: 0, y: 0, width: prog, height: 85)
animationProgress.transform = animationProgress.transform.scaledBy(x: 1, y: 85)
self.contentView.addSubview(animationProgress)
Actual tableview cell :
Progress view getting overlapped :
The issue you're having is related to the order of subviews. I'm not sure what cell you are you using how and when do you add other labels. But it looks like you need to send the UIProgressView to the back.
In your case the fix should be after calling self.contentView.addSubview(animationProgress) make sure to send the subview to the back which means calling self.contentView.sendSubviewToBack(animationProgress).
I created a view programmatically, like a popup coming from the top with some text and images in there!
alert = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width , height: 0))
alert?.frame.origin.y = (textLable?.frame.height)!
alert?.frame.size.height = (textLable?.frame.height)!
alert?.backgroundColor = self.arrayOptions.colorBackground
and then I'm trying to add a UITapGestureRecognizer to that view like this inside a setup func that is called in the init.
let tap = UITapGestureRecognizer(target: self, action: #selector(self.teste))
tap.numberOfTapsRequired = 1
alert?.addGestureRecognizer(tap)
im adding that view like this in a UitableViewController:
self.popView = PopupView(frame: CGRect(x: 0 , y: 0 , width:self.view.frame.width, height: 0), with: PopUpOptions.error, originY: 0,description:"blablabla")
self.view.addSubview(self.popView!)
But when I tap on the view nothing happens, but when I tap repeatedly over and over this error occurs:
<_UISystemGestureGateGestureRecognizer: 0x174186f50>: Gesture: Failed
to receive system gesture state notification before next touch
But I cant seem to find an answer for this, could anyone help me pls!
Thank you!
here is the GitHub link https://github.com/Coimbraa/AlertsPopup_framework for my framework
Took a look at your GitHub repo - Couple notes...
I see a lot of "!" in your code. Each one of those is a potential crash. For example, I had to make a number of edits just to get it to run at all (I don't have the image assets the code is expecting).
In PopUpView.swift change the init() func to this (just added the clipsToBounds line):
override public init(frame: CGRect) {
super.init(frame: frame)
setup()
self.clipsToBounds = true
}
Now, when you call popView?.toggleStatus() you probably won't see anything.
Your PopupView "container" has a height of Zero. Without clipping its contents, you see the content, but you can't interact with it.
I changed your animation block in toggleStatus() to this:
UIView.animate(withDuration: 0.5, animations: {
if let sz = self.alert?.frame.size {
self.frame.size.height = sz.height
}
self.alert?.frame.origin.y = (self.startY)! + (self.status ? 0 : -((self.textLable?.frame.height)! + self.startY))
}) { (finished:Bool) in
// ...
and I could now tap into and edit the TextView, and tap elsewhere and get print("pressed") output to the debug console.
I did not dig further, so I don't know if/where you need to put additional code to reset the frame-height back to Zero (or maybe it gets hidden or removed, whatever).
Try this:
alert.isUserInteractionEnabled = true
Set this property to true for those views you want to tap on (where you add the tap gesture recognizer).
You are adding that Custom Alert View in Table View Controller.
First try what Tung Fam has suggested, if it doesn't work then,
Trying adding it on window like:
self.view.window.addSubview(self.popView!)
Also set the frame of the window to the popupView.
As I'm seeing you are setting target for TapGesture as self in
let tap = UITapGestureRecognizer(target: self, action: #selector(self.teste))
Here self is object of UIView (your alert view).
So according to this line your tapGesture listener must be implemented in alert? class. And you need to use custom protocol or custom delegate to get the action of tapGesture in other classes.
I am creating a game for english typing. The words fall from the top to the edge of keyboard. For animating the fall of a label I have used:
UIView.animateWithDuration(25, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
label.frame = CGRectMake(self.view.frame.width - (label.frame.origin.x+label.frame.width), self.view.frame.height-self.keyboardYPosition!, label.frame.width, width)
}){(success) in
label.removeFromSuperview()
for label in self.currentLabelsArray {
label.layer.removeAllAnimations()
label.removeFromSuperview()
}
self.gameOver()
}
Everything goes fine. The problem I am facing is : I am calling this animation block on creation of every single label. Actually this animation block is in a function called createLabels(). And the createLabel function is called every 5 seconds using NSTimer. Once the game is over I show a view above with restart button. Now here comes the problem:
Before the game ends we might have 3-4 labels already created that are pushed into the animation block. But the very first label might end the game. I get a gameover view above it with a restart button. Once I tap restart, my game again ends because the labels created earlier are still calling the completion block of UIAnimation. I cannot restart the game unless all my labels have completed the animation.
Is there any way to remove animation once the game if completed so that the already created labels no more come into the completion block?
I have used the following code to remove the label from view and remove its animation:
for label in self.currentLabelsArray {
label.layer.removeAllAnimations()
label.removeFromSuperview()
}
A quick guess is that, perhaps you missed to invalidate the timer object.
for label in self.currentLabelsArray {
label.layer.removeAllAnimations()
label.removeFromSuperview()
}
myTimer.invalidate();
So the timer will not call createLabels after the 5 sec. Once the game restarts schedule the time again.
Hope that helps!
EDIT:
Another pointer could be to clear the labels array.
self.currentLabelsArray.removeAllObjects();
and call self.gameOver() iff, there is no request of game over in queue.
EDIT:
UIView.animateWithDuration(25, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
label.frame = CGRectMake(self.view.frame.width - (label.frame.origin.x+label.frame.width), self.view.frame.height-self.keyboardYPosition!, label.frame.width, width)
}){(success) in
//label.removeFromSuperview()
for label in self.currentLabelsArray {
label.layer.removeAllAnimations()
label.removeFromSuperview()
}
if(self.currentLabelsArray.count > 0) {
self.currentLabelsArray.removeAllObjects()
self.gameOver()
}
}
So the main screen of my app has a hamburger button which can be used to navigate to other parts of the app. That being said, there's a chance someone might get notifications in other parts of the app, so I'm trying to add an indicator, which is just a subclass of UILabel which shows up over the hamburger button. When the view first loads, it looks like this, which is fine:
Okay, so when the user opens the navigation drawer I animate the hamburger button and remove the notification by hiding it (self.badge.hidden = true), and it goes away fine, like this:
Now the problem I'm facing is that when the view is animated back in, the notification badge ends up in a really weird place, even though no frames change, and if I print out the frames, it's exactly where it should be programmatically, but it actuality it ends up looking really weird, as just the tiny bubble in the top left corner:
All I'm doing to add it back is in my delegate method for when the navigation drawer closes, I try self.badge.hidden = false. So obviously there's something weird going on here.
But what's even weirder, is that if I navigate to another view, say I press one of the buttons in the navigation drawer, and then go back to the home view, then the hiding works fine, and when I unhide the notification badge then it appears exactly where it should be! As I said, this only happens if I navigate away from the home screen and then back to it, but when the app first loads and I go to the navigation drawer, then the notification badge gets put in the wrong place and is also very tiny. I've tried a lot of things to try to get this to work. Originally I was reinitializing the badge view before I added it back using the same frame I did when the view loaded, but it still ended up the way it looks now. I also tried to set it to nil and remove it from the superView instead of just hiding it, but all of the different things I've tried have resulted in the same thing: only on the home screen before navigating elsewhere, the badge doesn't end up in the right place after closing the navigation drawer. I can post more code or answer any additional questions you might have, but please help me I can't figure this one out!
Here is my initialization code in viewDidAppear:
badge = SwiftBadge(frame: CGRectMake(15, -5, 15, 15))
menuButton.addSubview(badge!)
menuButton.bringSubviewToFront(badge!)
And creating my menuButton (which I do do in viewDidLoad)
menuButton = UIButton(frame: CGRectMake(0, 0, 20, 20))
menuButton.setBackgroundImage(UIImage(named: "Side menu.png"), forState: .Normal)
let addBarItem = UIBarButtonItem(customView: addButton)
let menuButtonItem = UIBarButtonItem(customView: menuButton)
self.navigationItem.setLeftBarButtonItem(menuButtonItem, animated: true)
EDIT 2:
Code for rotating the hamburger button
let animationDuration = self.revealViewController().toggleAnimationDuration
UIView.animateWithDuration(animationDuration, animations: { () -> Void in
if !self.menuButtonRotated {
//self.badge?.removeFromSuperview()
self.badge?.hidden = true
self.menuButton.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
self.menuButtonRotated = true
print("Menu frame after rotation: \(self.menuButton.frame)")
} else {
self.menuButton.transform = CGAffineTransformMakeRotation(CGFloat(0))
self.menuButtonRotated = false
self.badge?.hidden = false
}
}, completion: { (bool) -> Void in
if !self.menuButtonRotated {
//self.badge = SwiftBadge(frame: CGRectMake(250, 250, 100, 100))
print("New menu frame: \(self.menuButton.frame)")
print("New badge frame: \(self.badge!.frame)")
//self.view.addSubview(self.badge!)
//self.badge?.hidden = false
}
})
Commented out code is some other things I've tried.
Well after much debugging and hair pulling, I finally figured out what the fix was. For whatever reason it seems that my menuButton frame wasn't set as soon as the animation ended, so I had to change my animation code to below, hopefully this will help someone who comes looking later:
UIView.animateWithDuration(animationDuration, animations: { () -> Void in
if !self.menuButtonRotated {
self.badge?.hidden = true
self.badge?.removeFromSuperview()
self.badge = nil
self.menuButton.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
self.menuButtonRotated = true
print("Menu frame after rotation: \(self.menuButton.frame)")
} else {
self.menuButton.transform = CGAffineTransformMakeRotation(CGFloat(0))
self.menuButtonRotated = false
}
}, completion: { (bool) -> Void in
if !self.menuButtonRotated {
print("New menu frame: \(self.menuButton.frame)")
print("New badge frame: \(self.badge?.frame)")
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(0.05 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
self.badge = SwiftBadge(frame: CGRectMake(13, -7, 15, 15))
self.badge?.alpha = 0.95
self.menuButton.addSubview(self.badge!)
self.menuButton.layoutIfNeeded()
}
}
})
I'm new to Objective C and swift (I guess we are all new to swift) but I am trying to make a UIButton appear and disappear in different locations on the screen in my app. This is what I've tried in one of my view controllers so far but it doesn't seem to work.
func addButton() {
var start: CFTimeInterval
var elapsedTime:CFTimeInterval
let Button = UIButton()
let picture = UIImage(named: "picture.png")
Button.setImage(picture, forState: UIControlState.Normal)
Button.frame = CGRectMake(0, 142, 106.6, 106.5)
self.view!.addSubview(Button)
while (elapsedTime < 1.0) {
elapsedTime = CACurrentMediaTime() - start
}
Button.removeFromSuperView()
}
You could use the convenient GCD API for the timing
dispatch_after(dispatch_time_t(1.0), dispatch_get_main_queue(), {
button.removeFromSuperView()
})
If it is always the same button, it would be better to create a variable or outlet and just recycle the button (you just let it appear and disappear by setting the alpha or the hidden property. If it is just supposed to be blinking, you could use a basic CAAnimations instead.
NB: Please get into the habit of using variable names that start with small letters, or you will end up mistaking them for class names.