Swift: Add a label and place it underneath another label - swift

I want to create labels programmatically with text that comes from a database.
So a for loop is creating the labels with this function at the moment:
func fillScrollViewWithLabels() {
for message in messages {
let label = UILabel(frame: CGRectMake(0, 0, 200, 21))
label.text = message.message
self.chatScrollView.addSubview(label)
}
}
But this function puts the labels one above the other.
It should look like a messenger - the labels are the text messages and I think a scrollView is perfect for that.

You will need to make a variable for the Y position of your labels
var currentLabelYPosition : CGFloat = 0 // set to first y position
Then as you iterate through your array and create a label you'll need to get it's Y position based on the last labels Y position, like this:
for message in messages {
let label = UILabel(frame: CGRectMake(0, currentLabelYPosition, 200,21))
label.text = message.message
self.chatScrollView.addSubview(label)
currentLabelYPosition + label.frame.size.height // Update this accordingly with any type of padding, offset, etc.
}

I didn't fully understand your question but you're free to use Scrolview's subclass textview to store texts and than add different text in every message.
I suggest to check this github repo to familiarize concept of chat apps.
Edit
Also found this notification chat github repo much more lightweight sample to examine.

Update your code like this
var yPos:CGFloat = 0.0
let label = UILabel(frame: CGRectMake(0, yPos, 200, 21))
for message in messages {
let label = UILabel(frame: CGRectMake(0, yPos, 200, 21))
label.text = message.message
self.chatScrollView.addSubview(label)
yPos = yPos+21;// you can also add spacing if you want
}

Related

How to use frame to set x position in loop on Swift

I have an array that count is between 1 to 3 varies.
I want to frame them in the middle of the screen with a certain distance
Also the width of the labels is fixed
let array = ["some1", "some2", "some3"]
func setLabel(){
var i = -1
for text in array{
i += 1
let label = UILabel()
label.fram = CGRect(x: screenWidth/2 - (CGFloat(i)*50) + 25, y: 100, width: 50 , height: 20)
label.text = text
addSubview(label)
}
}
You can use stackview as suggested by #matt. If you don't want to use stackview you can calculate the x position by array count and label index like this
let array = ["some1", "some2", "some3"]
func setLabel(){
var i:CGFloat = 0
for text in array{
i += 1
let label = UILabel()
label.backgroundColor = .red
label.frame = CGRect(x: (view.bounds.width/CGFloat(array.count+1))*i-25, y: 100, width: 50 , height: 20)
label.text = text
view.addSubview(label)
}
}
The really easy way to do this is to put the labels (one, two, or three of them) into a centered UIStackView. You would still need to know the desired fixed width of a label and apply a width constraint to each label, but everything else will just take care of itself.
Just as a demonstration, I used an arbitrary width of 100, with the text for all three labels being just "UILabel" as in your image. Here's what it looks like with one label:
Here's what it looks like with three labels:
Here's the code I used (sv is the stack view, which has already been configured in the storyboard; n is how many labels we want):
for _ in 1...n {
let lab = UILabel()
lab.text = "UILabel"
lab.textAlignment = .center
lab.translatesAutoresizingMaskIntoConstraints = false
lab.widthAnchor.constraint(equalToConstant: 100).isActive = true
sv.addArrangedSubview(lab)
}
So all you really need to do is get the right text from your array as we loop, and you're done. The point is that you don't need to think about frames at all! The UIStackView imposes the correct the frames for us.
NOTE Although I said above that the stack view was "configured in the storyboard", that has nothing to do with the answer. You can create and configure the stack view in code just as well, without changing anything about my answer. The point is that the stack view already knows how to receive an arbitrary number of views, space them out evenly, and center them as a whole. That is what it is for. So if, as your question implies, you can't manage the arithmetic to assign the views a frame yourself, why not let the stack view do it for you?

UIScrollView wrong offset

I have several labels inside an scrollview. Each label is an "page". But the offset isn't right. And I can't find the problem.
My code:
let quantity = 10;
var width : CGFloat = 0.0;
override func viewDidLoad() {
super.viewDidLoad()
width = self.scrView.frame.width;
for i in 0..<quantity {
let xPos = width * CGFloat(i);
let label = UILabel(frame: CGRect(x: xPos, y: 0, width: width, height: self.scrView.frame.height))
label.textAlignment = .center
label.font = UIFont(name: "Helvetica Neue", size: 50)
label.textColor = UIColor.white
label.text = "\(i + 1)"
label.backgroundColor = .randomColor()
scrView.addSubview(label);
}
scrView.contentSize.width = width * CGFloat(quantity + 1);
}
The pink color on the left side is from the previous "page".
And again, note the purple color on the left side from the previous (number 8) page.
The first page seems fine. However the higher the number the greater the offset. I want to cover the whole visible area for 1 label.
Does somebody knows an solution?
Your code works fine for me.
Note that the size of the scrollView can change after viewDidLoad as a result of Auto Layout. A better place to set up your scrollView would be in an override of viewDidLayoutSubviews. The size of the scrollView will be established by then. But be careful, because viewDidLayoutSubviews will run multiple times, so make sure you only set up your scrollView once.
This is not your bug, but your contentSize.width is too big. You don't need to add 1 to quantity since there are exactly quantity labels in your scrollView content area.
scrView.contentSize.width = width * CGFloat(quantity)
Also, Swift doesn't need the ; at the ends of lines, so delete those.

How to insert Custom Label with text into View with Animation?

Im making a small boxing app. This whole week iv been trying to work out how to solve my current problem above, with no luck :(.
Summary
Basically Its a 1 v 1 game. Each time the user hits the other player I want to make a tiny number pop up near him and float up and dissappear.
Its sort of like when you play MMORPG's and when you do dmg you see how much you did. See image below for an example!
So basically everytime the user hits the other player I want a little number to pop up on the screen to show the dmg and then float up and disappear.
Details
I am building the game on a simple UIView
The label is a UILabel
Anywhere How I can achieve this?
Thank you!
Create a label, then use UIView.animateWithDuration to animate it.
let label = UILabel(frame: CGRect(origin: point/*The point where you want to add your label*/, size: CGSize(width: 50, height: 50)))
label.text = "+1"
label.font = UIFont()//Your font
label.textColor = UIColor.blueColor()
label.alpha = 1
self.view.addSubview(label)
UIView.animateWithDuration(1) {
label.center = CGPoint()//The point where you want your label to end up
label.alpha = 0
}
Edit: As mentioned in the comments, you asked for how to create the label at a random point. Try this:
let screenWidth = self.view.frame.width
let screenHeight = self.view.frame.height
let randomX = CGFloat(arc4random_uniform(UInt32(screenWidth)))
let randomY = CGFloat(arc4random_uniform(UInt32(screenHeight)))
let point = CGPoint(x: randomX, y: randomY)
As you will notice, for the width and height, I use the view's frame's width and height. You may want to use the view's bounds. For more on this, check out this SO Post.

Swift get Y coordinate of current element

I got some UILabel which can be pressed to open a menu. When pressed, they call my function with the label itself as a parameter. I make a popover that behave correctly in phone view but I would like to position it when it is on ipad view.
My problem is that I can not get the exact position of the UILabel that was pressed.
I tried
myYCoordinates = label.bounds.origin.y
or
myYCoordinates = label.frame.origin.y
to
optionMenu.popoverPresentationController?.sourceRect = CGRectMake(self.view.bounds.size.width / 2, myYCoordinates, 1.0, 1.0)
But I cant get the good coordinate.
I don't know if it is because my label are in a tableview with 2 section or if there is a way at all.
Thank in advance for the help.
Here is my sceen (cropped du to development confidentiality)
Here is what append when I press my label
And here is what I would like ti to look like
I tried
optionMenu.popoverPresentationController?.sourceRect = label.frame
Based on #Özgür Erzil answer, I found out that I could simply use
optionMenu.popoverPresentationController?.sourceView = label
optionMenu.popoverPresentationController?.sourceRect = CGRectMake(label.frame.width, label.frame.height / 2, 1.0, 1.0)
By setting the source view to my label and using the label width and height to position it.
Thank
if you create your UILabel dynamically, try to set the position when you set it like:
CGRectMake(x, y, width, height)
var label = UILabel(frame: CGRectMake(0, 0, 200, 20))
or if it is in storyBoard, you have to use constraint methods and use autolayout. Explained here

How to update UILabel that is a subview of inputView?

I have UITextView where user types a text. When the keyboard is shown, I add inputView with UIlabel on it. I want this UIlabel to hold character length of the text. It seems very easy task, but unfortunatelly it does not update this word counter UILabel when user change text..
this is how I load the inputView
_textView.inputView = [self inputAccessoryView];
in inputAccessoryView I simply add UILabel as a subview. When keyboard is show, UILabel is also show with inputView. I track changes on
- (void)textViewDidChange:(UITextView *)textView
unfortunatelly the UILabel is never updated (redrawn). When I log in to console its value, the value is correct, so its updating, but the UIlabel is never redrawn and holds the default value.
Can anyone help me with this?
did you
_textView.delegate = self;
?
I know it was 5 years ago, but it might help others, who like me stumble upon your question.
I use a UIToolbar as my inputAccessoryView (in my case it has a label, a flexible separator and a button).
On textFieldEditingChanged event I rebuild part of the toolbar like this
#IBAction func textFieldEditingChanged(_ sender: UITextField) {
//get a reference to the toolbar
let toolBar = sender.inputAccessoryView as! UIToolbar
//create a new label and set size + other properties
toolbarLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 40, height: 22))
toolbarLabel.text = mySpecificCalculatedString(sender.text!)
toolbarLabel.font = defaultFont(17)
toolbarLabel.adjustsFontSizeToFitWidth = true
let width = toolbarLabel.textRect(forBounds: CGRect(x: 0, y: 0, width: maxWidthForLabel, height: 0), limitedToNumberOfLines: 1).size.width
toolbarLabel.frame = CGRect(x: 0, y: 0, width: width, height: 22)
toolbarLabel.textColor = .black
toolbarLabel.tag = 666
//rebuild the specific tolbar item
let customView = UIBarButtonItem(customView: toolbarLabel)
toolBar.items![0] = customView
}
Note: simply changing the text of the label did not work for me either, I had to reinitialize it.
Hope it helps.