Swift UILabel with horizontal lines on both sides - ios

I am trying to create a UILabel that has 2 horizontal lines on the left and right side like this:
Does anyone know the best approach for doing this in Swift? The content text in the center will change so I want to make sure it can adapt. I'd really like to create some kind of reusable UIView class but I'm not sure where to start?
Thank you!

You can take two UIview of height 1 or 2 pixels of both side of the label. so it's look likes line!!
And you should set background color to black of that view!
Hope this will help :)

Take one UIView with height of 2. Set leading & Trailing according to Super View.
Now take one UILabel with background color white and put Vertically Center to line view.
Make both Center same.
Your work done.
For more help please refer below image.

You can use an extension on UILabel
public extension UILabel {
func drawLineOnBothSides(labelWidth: CGFloat, color: UIColor) {
let fontAttributes = [NSFontAttributeName: self.font]
let size = self.text?.size(attributes: fontAttributes)
let widthOfString = size!.width
let width = CGFloat(1)
let leftLine = UIView(frame: CGRect(x: 0, y: self.frame.height/2 - width/2, width: labelWidth/2 - widthOfString/2 - 10, height: width))
leftLine.backgroundColor = color
self.addSubview(leftLine)
let rightLine = UIView(frame: CGRect(x: labelWidth/2 + widthOfString/2 + 10, y: self.frame.height/2 - width/2, width: labelWidth/2 - widthOfString/2 - 10, height: width))
rightLine.backgroundColor = color
self.addSubview(rightLine)
}
}
This will add a horizontal line of width of 1.0 on the both side of your label. If you don't add text for your label, it will show two horizontal lines through center with some spaces in between them.

As others have mentioned, you can achieve this using three views:
Add a View to your scene to use as a container. I called this view "Lined Label Holder."
To that container, add two Views, one to produce the line on either side of the label.
Add the label in between the two views, and give it some text. Due to the "height = Test.height" constraint on the Lined Label Holder, The intrinsic height of this label is used to calculate the container's height.
The label is allowed to grow with added text and the lines will always start 5px away from the edges of the text and extended to the edges of the container, whose width can be set independently.
This image shows the required constraints:

Use one UIView with black background and height of 1px, set label background to white, align its text to center and align UILabel to center of UIView (there is no need for 2 views since label white background will cover UIView).

Not necessary 2 UIView's.
Take 1 UIView and give background black color.Add the constraints necessary with: height=2.
place 1 label on the center and give required constraints

Related

how to change size of customView passed as UICalanderView Decoration?

I could not find much detail about how to add a customView as decoration for UICalenderView. There are many blogs telling how to add images but could not find anyone about CustomView. In images, we can return the decoration item with size parameter however in case of customView there is no option to pass size along with customView that you are adding. So in the end, I was able to add a view with red background, but the size is wrong. I tried to create a view and give it frame but it had no effect. So im confused how to adjust its size. Here is the method in which I add customView that im creating:
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
return .customView(addActivityCircle)
}
And this is my addActivityCircle method which for now just creating a view with red background color:
private func addActivityCircle() -> UIView {
let view = UIView()
view.backgroundColor = .red
view.clipsToBounds = false
view.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
return view
}
When I run this code I do see a view with red color but it's like a small rectangle, not 50x50. If I pass small values like 20x20, I do see a small rectangle but anything above that I see a rectangle of fixed size. I think that's the limit of decoration item but in apps like Fitness app by apple, there are bigger activity rings than that so there should be a way to have bigger sized custom views as this is just too small. The width is fine but the height is just too less. This is what im getting and it does not get any higher than that:

UILabel can not be wrapped and aligned at the same time

I cannot wrap and align at the same time an UILabel displayed in a UITableViewCell.
I want some UILabels (displayed below with a white background) to be right aligned
and word wrapped if the text is too long. To clarify the sreenshots below:
UILabel with a white background are the labels I am talking about
I am using two different types of cell (respectively with blue and orange background)
The UITableView has a something-like-pink background
The ViewController in which the UITableView is displayed has a light gray background
Either is the alignment correct but the text is not wrapped (Actually the text "Long.. " is long, please see the second screenshot)
Or the text is correctly wrapped but it is not right aligned:
My code is based on this tutorial: How to build a Table View with multiple cell types
Inside the code for the cell displayed with an orange background:
class AttributeCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel?
#IBOutlet weak var valueLabel: UILabel?
let orange = UIColor(red: 1, green: 165/255, blue: 0, alpha: 1)
var item: AttributeLabelLabel? {
didSet {
titleLabel?.backgroundColor = .white
titleLabel?.setLabel(contentText: (item?.attributeNameFromLocalizable)!, alignmentText: .right)
valueLabel?.backgroundColor = .green
valueLabel?.setLabel(contentText: (item?.attributeValue)!, alignmentText: .left)
self.backgroundColor = orange
}
}
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
}
I added an extension to UILabel to set the alignment and text of the two labels displayed on cell, the way how the text should be wrapped is the same for all labels.
With the extension below the label is aligned but not wrapped (see first screenshot above).
extension UILabel{
func setLabel(contentText: String, alignmentText: NSTextAlignment){
self.text = contentText
self.textAlignment = alignmentText
self.numberOfLines = 0
self.lineBreakMode = .byWordWrapping // inefficient alone
}
}
If I want to have the text to be wrapped then I have to add a call to sizeToFit() but then short label (see label with the text "Short") is not right aligned (see second screenshot above).
extension UILabel{
func setLabel(contentText: String, alignmentText: NSTextAlignment){
self.text = contentText
self.textAlignment = alignmentText
self.numberOfLines = 0
self.lineBreakMode = .byWordWrapping
self.sizeToFit() // allow text to be effectivly wrapped
}
}
Why do I need to specify self.sizeToFit() on the documentation I have found only the use of lineBreakMode is mentionned to wrap a text ?
As I can not handle word wrapping and text alignement, I had the idea to compare the width of the UILabel with its text, and depending on the comparaison handling the alignment (for a text short enough) or the wrapping (if the text is too long). But I did not find how to get the UILabel´s width.
Another idea would be to create a custom UILabel and set all constraint, compression and resistance in code. For now there are no constraints:
Has someone already dealt with such problems?
Is it possible to handle text wrapping and text alignement at the same time ?
Note:
On the second screenshot the UILabel with a wrapped text overlapped the cell boundaries. It is not the first problem and I can live with that for now but if someone has an hint about that...
I actually use the following code to deal with cell with different heights:
cell?.estimatedRowHeight = 200
cell?.rowHeight = UITableView.automaticDimension
You are missing a few constraints.
To get a multiline label to wrap, it must have its width limited (how else would it know the text is too long?).
To get auto layout to adjust the cell's height, you need constraints on the content of the cell to "push down" the bottom of the cell.
So...
Constrain your top-left label to Leading: 0, Top: 0, Width: 77 (I'm using 77 as the width, based on your images).
Constrain your top-right label to Leading: 8 (to top-left label's trailing), Top: 0, Trailing: 0
Constrain your bottom-left label to Leading: 0, Top: 8 (to top-left label's bottom), Width: 77 (or, width equal to top-left label)
Constrain your bottom-right label to Leading: 8 (to bottom-left label's trailing), Top: 8 (to top-right label's bottom, or Top: 0 to top of bottom-left label), Trailing: 0
then, add Bottom constraints of >= 0 to each of the bottom labels.
I'm guessing either bottom label may wrap to multiple lines, so set each one to Number of Lines: 0
The layout:
the result:
A UILabel can definitely be right-aligned and wrap on multiple lines. Here is an example:
Actually, the label content is misleading as it wraps on four lines! ;-)
This can be achieved through AutoLayout constraints and the right settings on the UILabel. This particular UILabel is constrained as follows:
Vertically centred
Leading edge to super view
Width
Here are the constraints, as shown in Interface Builder:
Finally, to have a UILabel line-wrap to multiple lines, its numberOfLines property needs to be set to 0, either through Interface Builder or code.
You can also right-align the text using the textAlignment property, setting it to .right, again through Interface Builder or code.

Setting space within certain elements within a stackview

Essentially I am trying to create a UIStackView with some elements that has top margins and bottom margins. For example
| item one |
| item two |
| |
| itemfour |
I have tried to add a spacerView :
let textField1 = UITextField(text: "one")
let textField2 = UITextField(text: "two")
let textField3 = UITextField(text: "four")
let spacerView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
viewStack.addSubView(textField1)
viewStack.addSubView(textField2)
viewStack.addSubView(spacerView)
viewStack.addSubView(textField3)
However, the height that i am setting the spacerView does not seem to effect the space that is being created in the stack view.
PS: If there is a better way of adding top and bottom margins between two items, I am definitely open to it as adding a UIView feels really hacky
You could:
Make a spacer view that's a UILabel with text of a single space (" "). This will give you a blank row that's the same height as the rest of your text. This will work if the distribution is set to fillEqually (it works in other modes too, but I mention it because distribution matters in option #2 below).
or,
Create a subclass of UIView and override its intrinsicContentSize, returning a CGSize that specifies the height you want. Don't set this view's frame (i.e. let the UIStackView manage the view's frame). Note that this method only works if the distribution of the UIStackView is not set to fillEqually.

Full width view does not contain same frame width as parent

I'm having an issue where I have a UIImageView that spans the entire width of the screen using the following constraints.
Align Leading to : Superview (Equals: -20)
Align Trailing to : Superview (Equals: -20)
Top Space to : Top Layout Guide (Equals: 0)
Aspect Ratio : 1:1
The image assumes the width of the screen while gaining aspect ratio (in this case a square). The issue comes with when I started attempting to make a circle out of the image, that I noticed that my UIIMageView's frames do not have proper values.
You'll have to excuse to code below for not being in Objective-C as I'm using Java through RoboVM but with very little effort you can mentally convert the code to Objective-C as it's pretty straightforward.
public class MyViewController extends UIViewController {
#IBOutlet private UIImageView myImageView;
#Override public void viewDidLoad() {
System.out.println("Image view width: " + myImageView.getFrame().getWidth());
System.out.println("Superview width: " + this.getView().getFrame().getWidth());
}
}
The results of running the application with this Controller shows the following:
Image view width: 240.0
Superview width: 320.0
When cutting the frame width of the image in half and applying that to the CALayer#cornerRadius property, the image does not make a complete circle, however when using half of the superviews width (Which is actually the size of the image) the result is a perfect circle.
In viewDidLoad, it has just loaded your view from the XIB or storyboard, not sized it yet. The size should be correct when viewWillAppear is called. So try putting your code in viewWillAppear and see if that helps.
The reason you need the -20 margin is because your superview has a margin of 20, and the constraints are created by default to 'Relative to margin' - if you uncheck that, you can set the 'real' constraint - in this case zero rather than -20
If you select the constraint in the assistant editor, you will see the check box to toggle this value

Swift: programmatically align labels for different IOS screen sizes

I'm new to Swift and ios development. I have 6 labels and a horizontal SKScene in my App. I would like to align those 6 labels beautifully and automatically. Now I have fixed the positions and the alignment always looks awful on some screen size while good on other.
I have not used storyboards or other graphical editors for building the ui but everything is done in code. Therefore I'm looking for a programmatic solution (code examples) for handling the alignment.
If you want to place them in the middle of the screen horizontally, but give them different y positions, you could just do something like this for each label:
label.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMaxY(self.frame) * 0.80)
To place them at different y positions, just multiply by the maxY by a different decimal number. This way, all of the labels are aligned along the x-axis and appear at different y-positions, like a column and they will appear this way on every screen size because they are positioned relative to the screen size and not in a fixed position.
You can align the labels (lets say at the center of the screen) like this.
var label1 = UILabel(CGRectMake: 0, 0, 200, 40)
label1.center = CGPointMake(UIScreen.mainScreen().bounds.size.width/2, 30)
var label2 = UILabel(CGRectMake: 0, 0, 200, 40)
label2.center = CGPointMake(UIScreen.mainScreen().bounds.size.width/2, label1.center.y + 30)
and so on. Just reference the main screen bounds and not static points for alignment, so that they are centered in any screen size.
What I ended up doing was to create an empty SKSprite to which I included the SKLabels. Now I can control by the pixed the distances between labels but align the top-level sprite in the middle of the screen despite screen size.

Resources