I used the code below to create a label every time a button is pressed, then have the label move to a specific location, and then have it delete.
My problem is it can't create multiple labels because it's deleting the label way too soon, because it removes everything named label.
How can I fix this so it creates multiple labels that only get deleted when a label individually completes its animation?
A solution I've thought of, but can't figure out is where you have it create a label with a different name such as label1, label2, and so on, so that way it can delete a specific label when it completes it's animation, instead of deleting all of them.
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
func createLabel() {
// Find the button's width and height
let labelWidth = label.frame.width
// Find the width and height of the enclosing view
let viewWidth = self.view.frame.width
// Compute width and height of the area to contain the button's center
let xwidth = viewWidth - labelWidth
// Generate a random x and y offset
let xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))
// Offset the button's center by the random offsets.
label.center.x = xoffset + labelWidth / 2
label.center.y = 300
label.font = UIFont(name:"Riffic Free", size: 18.0)
label.textColor = UIColor.white
label.textAlignment = .center
label.text = "+1"
self.view.addSubview(label)
}
func clearLabel() {
UIView.animate(withDuration: 0.9, delay: 0.4, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: .curveLinear, animations: {
self.label.center = CGPoint(x: 265, y: 75 )
}, completion: { (finished: Bool) in
self.label.removeFromSuperview()
})
}
#IBAction func clicked(_ sender: Any) {
createLabel()
clearLabel()
}
The problem is with this code:
#IBAction func clicked(_ sender: Any) {
createLabel()
clearLabel()
}
There are two issues. The first is that you are doing the animation and removal before you even give the label a chance to become part of the interface. You need to introduce a delay (you can use my delay utility, https://stackoverflow.com/a/24318861/341994):
#IBAction func clicked(_ sender: Any) {
createLabel()
delay(0.1) {
clearLabel()
}
}
The second problem, as you have rightly said, is that you have one label instance variable, which you are using to share the label between createLabel and clearLabel. Thus another label cannot come along during the animation.
But you don't actually need any instance variable. So get rid of your label declaration completely! Instead, modify createLabel so that it actually creates the label (i.e. calls UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))) as a local variable, and then returns a reference to label it creates, like this:
func createLabel() -> UILabel {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
// ...
return label
}
... And then just have clearLabel take that same label as a parameter so that it moves that label and removes it at the end of the animation, like this:
func clearLabel(_ label : UILabel) {
// ...
}
Your clicked implementation will thus look like this, passing the label out of createLabel and into clearLabel:
#IBAction func clicked(_ sender: Any) {
let label = self.createLabel()
delay(0.1) {
self.clearLabel(label)
}
}
(The remaining details of modifying createLabel and clearLabel to make that work are left as an exercise for the reader.)
Now each tap on the button creates and animates and removes a new label, independently of whatever else may have happened before.
Related
I'm new in Swift programming. I have a problem with an animation of a view when i try to change the text of a UITextView.
This is a method that is triggered from a button that is in the main view. self.parkingMenuTittle is a UITextView that i also have in the main view. When the button is triggered I want to change the text and set the view height to the ycomponent variable that my code has, but the view instead of doing that, goes to the original size. If I don't update the UITextView text my animation works just fine.
#objc func seeMore(_ sender: UIButton){
self.parkingMenuTittle.text = "test"
UIView.animate(
withDuration: 0.2,
animations: {
let frame = self.view.frame
let ycomponent = UIScreen.main.bounds.height-300
self.view.frame = CGRect(x: 0, y: ycomponent, width: frame.width, height: frame.height)
},completion: { (finished: Bool) in
//Code
})
}
I also tried to put the text in the completion block but don't work.
Thanks for your help!
I am trying to allow the user to rotate text they place on a view inside UITextViews. The problem is when I rotate them using the transform property, the text gets cutoff. However, when I do this with UILabels, it works fine, so why not UITextViews? The bounds of UITextView (shown in green) never changes, so I am not sure why this is happening. The amount of cutoff seems related to the height of the text view.
The only work around I've found is to do the transform asynchronously. I don't know why it works, but I don't think it's a good solution. You can see this in action with the following code.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
for xPos in stride(from: 80, to: view.bounds.width, by: 80) {
let point = CGPoint(x: xPos, y: 100)
let textView = makeTextView(at: point)
//DispatchQueue.main.async {
let angle = xPos / 400.0
textView.transform = CGAffineTransform(rotationAngle: angle)
//}
view.addSubview(textView)
}
}
private func makeTextView(at point: CGPoint) -> UITextView {
let textView = UITextView()
textView.text = "1234567890"
textView.isScrollEnabled = false
textView.backgroundColor = .green
textView.center = CGPoint(x: point.x, y: point.y)
textView.bounds.size = CGSize(width: 80, height: 24)
return textView
}
}
What is the correct way to rotate them?
I have a UIView that's centered vertically and horizontally in my storyboard and has a fixed height (100) and width (300). Now I want that uiview to be resized (100, 100) during runtime.
I have tried this so far but nothing worked.
let cgRect = CGRect(x: 0, y: 0, width: 100, height: 100)
sampleView.draw(cgRect)
and
sampleView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
and
sampleView.frame.size.height = 100
sampleView.frame.size.width = 100
Hook the width and height constraints as IBOutlet and in
#IBAction func btnClicked(_ sender: Any) {
self.widthCon.constant = 100
self.heightCon.constant = 100
self.view.layoutIfNeeded()
}
To change the constraints during runtime via a button press you need to add it in an IBAction. In order to animate the change rather than it just jump, put the code in the UIView animation method:
#IBAction func buttonPressed() {
self.widthCon.constant = 100
self.heightCon.constant = 100
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
})
}
You can do this:
override func layoutSubviews() {
super.layoutSubviews()
// set hight and width by constraints.
}
or:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// set hight and width by constraints.
}
In my project I have a pinch to resize option for the object that has been placed in scene view. But when someone pinch the screen to reduce or enlarge the actual size of the object I need to get that scale. I need to display the scale in which the object is being changed in the screen. How do I get the scale when the action is being performed?
Thank you
Within your main ViewController Class for the ARSCNView
declare the label view, and the label itself at the top.
let scaleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 300, 70))
let labelView = UIView(frame: CGRect(x: 300, y: 300, width: 300, height: 70))
Now within LoadView or ViewDidLoad you can set the attributes for the label such backgroundColor, textColor etc... and also add the view and label to sceneView.
// add your attributes for label,view
labelView.backgroundColor = .clear
scaleLabel.textColor = .white
scaleLabel.adjustsFontSizeToFitWidth
// add you views to sceneView
labelView.addSubview(scaleLabel)
sceneView.addSubview(labelView)
Lastly, with the pinch gesture function for scaling.. which should look something like this.
#objc func pinchGesture(_ gesture: UIPinchGestureRecognizer) {
if nodeYouScale != nil {
let action = SCNAction.scale(by: gesture.scale, duration: 0.1)
nodeYouScale.runAction(action)
gesture.scale = 1
// this part updates the label with the current scale factor
scaleLabel.text = "X: \(nodeYouScale.scale.x) Y: \(nodeYouScale.scale.y) Z:\(nodeYouScale.scale.z)"
} else {
return
}
I am trying to add buttons dynamically to a scroll view after pressing another button.
I created a custom UIView which I want to add to the scroll view.
Below you can find the code how I am trying to do it:
var buttonY: CGFloat = 0 // our Starting Offset, could be 0
for _ in audioCommentsArray {
UIView.animateWithDuration(0.15, animations: {
let commentView = AudioCommentView(frame: CGRectZero)
commentView.frame = CGRect(x: 0, y: buttonY, width: 75, height: 75)
buttonY = buttonY + 75 // we are going to space these UIButtons 75px apart
commentView.alpha = 1.0
audioCommentsListScrollView.addSubview(commentView)
})
}
I want to add these commentView's using a simple animation. However only the last commentView is added correctly to the scrollView whereas the above views are added like this:
Only the background of the commentView is shown whereas the other elements are not visible.
Does anyone have an idea what I might be missing? Adding views using a for loop shouldn't be complicated as I have done this many times before but this time I seem to miss something?
Thank you in advance!
The UIView animations are overlapping and interfering with each other as you process them through the loop. Instead, you should chain them so that the next animation does not interfere with the other. Delete the loop. Then call the animations one after the other in the completion handler. You can call it recursively to ensure each button is animated.
var count = 0
func startButtonsAnimation() {
UIView.animateWithDuration(0.15, animations: {
let commentView = AudioCommentView(frame: CGRectZero)
commentView.frame = CGRect(x: 0, y: buttonY, width: 75, height: 75)
buttonY = buttonY + 75 // we are going to space these UIButtons 75px apart
commentView.alpha = 1.0
audioCommentsListScrollView.addSubview(commentView)
}, completion: { (value: Bool) in
if self.count < self.audioCommentsArray.count {
self.count += 1
self.startButtonsAnimation()
}
})