How to vertically center a font glyph? - ios

I have a UIButton with title "⟳". The title does not appear to be vertically centered due to the position of "⟳".
I understand that offsets of the UIButton can be changed to solve the problem in this instance.
Can anyone point out if there is any other way to vertically center the "⟳" glyph?

In this image, all 4 green buttons are using 64-pt System font, with the .titleLabel background set to yellow:
As you can see with the top button, an upper-case "O" is centered vertically and horizontally.
The "⟳" unicode symbol you are using is more like a lower-case character - as seen in the 2nd button.
By itself, in the 3rd button, we see it appears "shifted" down and to the left.
The symbol in the bottom button is center-aligned by adjusting the Title Edge Insets:
.titleEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 14, right: 0)

Related

How to center a SF Symbols image vertically in UITabBarItem?

I am using SF Symbols images as tab images in my iOS app by assigning them as follows:
self.tabBarItem.image = UIImage(systemName: "ellipsis")
This results in all images being top-aligned, but I would like to have them centered vertically.
What do I have to do for this?
Apparently SF symbols are rendered with system font size by default. So if you add a baseline offset of half that size to the ellipsis symbol you could almost perfectly center it vertically that way.
It's only almost perfect because ellipsis symbol has a height of its own which is not accounted for by this solution, even if it is not much.
self.tabBarItem.image = UIImage(systemName: "ellipsis")!.withBaselineOffset(fromBottom: UIFont.systemFontSize / 2)
The best solution, which will make your button identical to "tabBarSystemItem: .more", but with the possibility of removing the title and applying Configuration is the following:
self.tabBarItem.image = UIImage(systemName: "ellipsis", withConfiguration:
UIImage.SymbolConfiguration(weight: .black))!.imageWithoutBaseline()
You have to set the image insets on the UITabBarItem to shift your icons down 6 or 7px (depending on your icon size).
In code:
I've done this by creating a subclass of UITabBarController and adding this code to the bottom of my viewDidLoad method:
tabBar.items?.forEach({
$0.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
})
(You could also do this in your ViewController classes, if that's where you configure each of their tab bar items.)
In storyboards:
You can also do it using storyboards by selecting your TabBarItem in the storyboard and adjusting the insets in the info panel:

Positioning UIScrollView scrollIndicatorInsets to edges, no spacing?

How does the ScrollView.scrollIndicatorInsets actually work ?
If you set all insets to 0 as default, and you do some debugging you will actually find that the scrollbar isn't exactly near the bottom or right edges by default as it should be.
ScrollView.scrollIndicatorInsets = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
As you can see, there is some extra spacing between the scrollbar and the scroll view edges.
Is there any way that I can place the scrollbar bottom left corner exactly at the bottom left corner of the view programatically ? I don't want to hardcode anything, I want it to work on any scrollview size and screen.
What do the insets actually specify (yes, I know they specify a rectangle for the scrollbar) ? Is there a default spacing-to-edge that iOS uses for the scrollbar and I have to take that into consideration ? Is there glow on the scrollbar's layer view, hence the spacing ?
EDIT:
I solved this using the non-convential approach by accessing the UIView from the scrollbar itself (subviews.last), and using the smallest size (which is the thickness).
Quick inspection shows the Scroll Indicators with Insets set to UIEdgeInsetsZero (the default) places them 3-pts from the edges.
You can try using:
theScrollView.scrollIndicatorInsets = UIEdgeInsets.init(top: -3, left: -3, bottom: -3, right: -3)
which should align the horizontal indicator flush to the bottom, and flush with the left and right edges, and the vertical indicator flush to the right, and flush with the top and bottom edges.
You might want to get the frame(s) first though, as it's possible it varies between devices / sizes / iOS versions.
Edit:
A couple clarifying notes...
The scroll indicators are image views. You can find them by inspecting the scroll view's subviews (code or with Debug View Hierarchy).
The default insets (of Zero) put those image views 3-pts from the edge of the scroll view's frame.
With a 300 x 500 scroll view, the origin of the vertical indicator is:
x:294.5 y:3.0 with a width of 2.5
294.5 + 2.5 == 297
// 3-pts from the right edge, 3-pts from the top
and the origin of the horizontal indicator is:
x:3.0 y:494.5 with a height of 2.5
494.5 + 2.5 == 497
// 3-pts from the left edge, 3-pts from the bottom
So, using:
.scrollIndicatorInsets = UIEdgeInsets.init(top: -3, left: -3, bottom: -3, right: -3)
moves the origins to
// vertical
x:297.5 y:0.0 with a width of 2.5
297.5 + 2.5 == 300
// flush to top and right edges
// horizontal
x:0.0 y:497.5 with a height of 2.5
497.5 + 2.5 == 500
// flush to left and bottom edges
I suppose it's possible that could change in the future. As fewer and fewer people use devices with small screens, Apple could change the width/height to 3 or 3.5 or whatever, and could change the default inset from 3 to something else. Which is why I said you might want to get the frames to get the proper inset values, rather than hard-coding them to 3.
Curiously, though, until the indicator frames have been drawn to the screen - either by flashing them or actually scrolling the content - their frames are set to 7-pts in height (for the vertical indicator) and 7-pts width (for the horizontal), and positioned at the bottom-right corner.
So, with the 500 x 300 scroll view frame, the indicator frames are initially:
// vertical
x:294.5 y:490.0 w:2.5 h:7.0
// horizontal
x:290.0 y:494.5 w:7.0 h:2.5
That still tells you they are 3-pts from the edges, but it's not quite as clear... and again, no guarantee that won't change in the future.
If you really want sure the indicators will go where you want them, your best bet may be to use custom views instead of the built-in indicators.

UITabBarItem - Position image separately from title text

I have a UITabBar with 5 UITabBarItems, each containing an image and a title. Currently, the images are positioned centered above the title text. When an item is selected I bold the text, however this causes the positioning of the image to change slightly since the text now takes up more space. How can I divorce the positioning of these two elements in a UITabBarItem?
Try adjusting the image insets to get your desired look.
For example, you could try:
tabBarItem.imageInsets = UIEdgeInsets(top: -1, left: 0, bottom: 1, right: 0)

Swift UILabel with horizontal lines on both sides

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

How to change Button Title Alignment in Swift?

I am trying to set the title on a Button to left. But everything i tried is not working.
With:
UILabelButton.titleLabel.textAlignment = .Left
Or:
UILabelButton.contentVerticalAlignment = UIControlContentVerticalAlignment // There is no left
The button title is still centered.
Is there another Property?
Use contentHorizontalAlignment.You have to use UIControlContentHorizontalAlignment.Left.You need to usehorizontal not vertical.
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
Swift 3.x
btn.contentHorizontalAlignment = .left
Swift 4
Sample code
For my requirement I want alignment left top
btnAddress.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
btnAddress.contentVerticalAlignment = UIControlContentVerticalAlignment.top
Swift 5 update:
btnAddress.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
btnAddress.contentVerticalAlignment = UIControl.ContentVerticalAlignment.top
btnAddress.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
btnAddress.contentVerticalAlignment = UIControl.ContentVerticalAlignment.top
And now if you want the text to have some space from left add this
btnAddress.titleEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)
You can also use the below solution (using Storyboard)
step1 :
set the horizontal alignment to left
By default button property have left content inset set to 10 i.e padding for the button from left side
you can see in the below image the left content inset is set to 10 for Left
so change that to 0, if you don't need any padding from left or set the number you want
This way you can set the button title to Left aligned
like this with swift 4:
btnAddress.contentHorizontalAlignment = .center
The Most Easiest and smallest Solution:
Button("0"){}.frame(width:160.0,height:70.0,alignment:Alignment.leading)
Check this by using this code for a button you will see that button text is now aligned to "LEFT"

Resources