Font Character Height Change in iOS - ios

I am trying to see if there is a proper method to change the height of the text, without changing the width - more akin to vertical compression. Photoshop lets you do it as shown below:
There are methods to change different attributes in text with NSAttributedString, but I didn't see one to change the height listed here:
https://developer.apple.com/documentation/foundation/nsattributedstring/key

You can do this by applying a scale CGAffineTransform.
Quick example using two identical labels, each with font set to .systemFont(ofSize: 32.0, weight: .regular), but the second label scaled to 50% height:
class ScaledLabelVC: UIViewController {
let v1 = UILabel()
let v2 = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
[v1, v2].forEach { v in
v.text = "This is a string."
v.font = .systemFont(ofSize: 32.0, weight: .regular)
v.backgroundColor = .yellow
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
v1.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
v1.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
v1.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
v2.topAnchor.constraint(equalTo: v1.bottomAnchor, constant: 8.0),
v2.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
v2.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
v2.transform = CGAffineTransform(scaleX: 1.0, y: 0.5)
}
}
Result:

Related

ContentView isn't Showing up Inside ScrollView

I'm having trouble getting my ContentView to show up inside my ScrollView and I don't know what I'm doing wrong to make it not visible. In my screenshot down below, the purple view is my ScrollView which is showing perfectly, and as you will see in my code, my ContentView is red. I tried to change my properties to lazy var to see if that would work, but I'm still having the same issue. Am I doing something wrong in my programmatic UI for my ContentView not to show up, or am I missing something? Thank you!
Screenshot of Problem
FindEmployeeJobRequestController
// MARK: - Properties
lazy var jobInfoCardView: ShadowCardView = {
let view = ShadowCardView()
view.backgroundColor = .white
view.addShadow()
view.setHeight(height: 320)
return view
}()
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.backgroundColor = .darkPurpleTint
sv.isScrollEnabled = true
return sv
}()
let contentView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
// MARK: - Helper Functions
fileprivate func configureUI() {
view.addSubview(jobInfoCardView)
jobInfoCardView.anchor(top: circularProgressView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor,
paddingTop: 52, paddingLeft: 24, paddingRight: 24)
jobInfoCardView.addSubview(scrollView)
scrollView.anchor(top: jobInfoCardView.topAnchor, left: jobInfoCardView.leftAnchor,
bottom: jobInfoCardView.bottomAnchor, right: jobInfoCardView.rightAnchor,
paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4)
jobInfoCardView.addSubview(contentView)
contentView.anchor(top: scrollView.contentLayoutGuide.topAnchor, left: scrollView.contentLayoutGuide.leftAnchor,
bottom: scrollView.contentLayoutGuide.bottomAnchor, right: scrollView.contentLayoutGuide.rightAnchor)
contentView.anchor(left: scrollView.frameLayoutGuide.leftAnchor, right: scrollView.frameLayoutGuide.rightAnchor)
}
UPDATE
I tried to add my contentView to my scrollView's subview, but it's still not showing. I even tried to add an UIStackView to my contentView to see if that could make it visible, but still not visible.
Updated Screenshot
Updated Code
fileprivate func configureUI() {
scrollView.addSubview(contentView)
contentView.anchor(top: scrollView.contentLayoutGuide.topAnchor, left: scrollView.contentLayoutGuide.leftAnchor,
bottom: scrollView.contentLayoutGuide.bottomAnchor, right: scrollView.contentLayoutGuide.rightAnchor)
contentView.anchor(left: scrollView.frameLayoutGuide.leftAnchor, right: scrollView.frameLayoutGuide.rightAnchor)
waitingOnEmployeeStack.axis = .vertical
waitingOnEmployeeStack.distribution = .fillEqually
waitingOnEmployeeStack.spacing = 4
contentView.addSubview(waitingOnEmployeeStack)
waitingOnEmployeeStack.centerX(inView: contentView)
waitingOnEmployeeStack.anchor(top: contentView.topAnchor, paddingTop: 5)
}
I think you wanted to add the contentView as a subView of the scrollView.
fileprivate func configureUI() {
view.addSubview(jobInfoCardView)
jobInfoCardView.anchor(top: circularProgressView.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor,
paddingTop: 52, paddingLeft: 24, paddingRight: 24)
jobInfoCardView.addSubview(scrollView)
scrollView.anchor(top: jobInfoCardView.topAnchor, left: jobInfoCardView.leftAnchor,
bottom: jobInfoCardView.bottomAnchor, right: jobInfoCardView.rightAnchor,
paddingTop: 4, paddingLeft: 4, paddingBottom: 4, paddingRight: 4)
scrollView.addSubview(contentView)
contentView.anchor(
top: scrollView.contentLayoutGuide.topAnchor,
left: scrollView.contentLayoutGuide.leftAnchor,
bottom: scrollView.contentLayoutGuide.bottomAnchor,
right: scrollView.contentLayoutGuide.rightAnchor
)
contentView.anchor(
left: scrollView.frameLayoutGuide.leftAnchor,
right: scrollView.frameLayoutGuide.rightAnchor
)
}
I think you might want to add contentView as scrollView's subview and not jobInfoCardView's subview
Couple notes...
I strongly recommend using standard constraint syntax - at least while you're learning. We don't know if your .anchor(...) funcs are doing the right thing, and when you review your code it's not entirely clear what might be happening. Once you've really gotten the hang of auto-layout, you may find it easier to use "helper funcs" (personally, I don't).
Also - use comments so both you and we know what your intent is.
Take a look at this...
You haven't shown what ShadowCardView might be, so we'll start with just a plain UIView subclass:
class ShadowCardView: UIView {
}
And an example controller class:
class ViewController: UIViewController {
lazy var jobInfoCardView: ShadowCardView = {
let view = ShadowCardView()
view.backgroundColor = .white
return view
}()
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.backgroundColor = .purple // .darkPurpleTint
return sv
}()
let contentView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
let circularProgressView: UIView = {
let view = UIView()
view.backgroundColor = .green
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 0.2, green: 0.6, blue: 0.8, alpha: 1.0)
// we'll be using auto-layout constraints for all views
[jobInfoCardView, scrollView, contentView, circularProgressView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
// add views
view.addSubview(circularProgressView)
view.addSubview(scrollView)
scrollView.addSubview(contentView)
contentView.addSubview(jobInfoCardView)
// respect safe area
let safeG = view.safeAreaLayoutGuide
// to make things a little more readable
let contentG = scrollView.contentLayoutGuide
let frameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// let's put the circularProgressView 20-points from the Top
circularProgressView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 20.0),
// 60-points on each side
circularProgressView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 60.0),
circularProgressView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -60.0),
// and give it 1:1 ratio
circularProgressView.heightAnchor.constraint(equalTo: circularProgressView.widthAnchor),
// let's put the scrollView 20-points from the Bottom of the progress view
scrollView.topAnchor.constraint(equalTo: circularProgressView.bottomAnchor, constant: 20.0),
// 20-points on each side
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 20.0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -20.0),
// and give it 1:1 ratio
scrollView.heightAnchor.constraint(equalTo: scrollView.widthAnchor),
// constrain all 4 sides of contentView to scrollView's Content Layout Guide
// and we'll use 12-points "padding" so we can see its frame inside the scrollView
contentView.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 12.0),
contentView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 12.0),
contentView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: -12.0),
contentView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: -12.0),
// set the Width of contentView to the Width of scrollView's Frame Layout Guide
// mius 24-points (12 on each side)
contentView.widthAnchor.constraint(equalTo: frameG.widthAnchor, constant: -24.0),
// constrain all 4 sides of jobInfoCardView to contentView
jobInfoCardView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0.0),
jobInfoCardView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0.0),
jobInfoCardView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0.0),
jobInfoCardView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0.0),
])
}
}
When run, it will look like this (green view is your circularProgressView and purple view is the scroll view):
That's pretty much what you are already getting. That's because - at the moment - ShadowCardView has no content to control its size. So, it's not even visible.
Let's change ShadowCardView to this:
class ShadowCardView: UIView {
let stackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 20
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
NSLayoutConstraint.activate([
// constrain all 4 sides of stackView to self
// and we'll use 8-points "padding" so we can see its frame
stackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 8.0),
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8.0),
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -8.0),
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8.0),
])
// give the stackView a border so we can see its frame
stackView.layer.borderColor = UIColor.systemBlue.cgColor
stackView.layer.borderWidth = 1
// add some labels
for i in 1...30 {
let v = UILabel()
v.text = "Label \(i)"
v.backgroundColor = .cyan
stackView.addArrangedSubview(v)
}
}
}
We've added a vertical stack view with 30 labels (along with proper constraints), and the output is now:
and we can scroll:

constraints not working programmatically swift

func textFields() {
let nameField = MDCFilledTextField()
view.addSubview(nameField)
nameField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
nameField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
nameField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
nameField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
nameField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
nameField.placeholder = "Name"
}
I am using google material design and create a textfield.For this purpose and i have used this code i want to space from both sides left and right but it works only one side left or right i want to space from both side.
You are trying to set the MDCFilledTextField position in a wrong way. The following line tells your view to use a static predefined frame size:
let estimatedFrame = CGRect(x: 10, y: 200, width: UIScreen.main.bounds.width-20, height: 50)
let nameField = MDCFilledTextField(frame: estimatedFrame)
But further down with the following rows you tell your view to use autolayout:
nameField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
nameField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
nameField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
nameField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
nameField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
So now you have to decide which one would you like to use, the static frame or the autolayout. If you decide to go with the autolayout you have to improve your code in order to remove the error you get. First you need to set the translatesAutoresizingMaskIntoConstraints to true instead of false.
nameField.translatesAutoresizingMaskIntoConstraints = false
This line will tell that you want to use the autolayout for nameField instead of a static frame. Further you need to add your view to the superview first, otherwise you can't define your constraints(therefore the error you have). So your code becomes:
func textFields() {
let nameField = MDCFilledTextField()
view.addSubview(nameField)
nameField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
nameField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10),
nameField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
nameField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
nameField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
nameField.placeholder = "Name"
}
Add the nameField as a subview of the view before activating the constraint and remove of using frames.
To add padding use for example centerXAnchor and widthAnchor + multiplier
func textFields() {
let nameField = MDCFilledTextField()
nameField.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(nameField)
NSLayoutConstraint.activate([
nameField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
nameField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
nameField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
nameField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9)
])
nameField.placeholder = "Name"
nameField.label.text = "Name"
nameField.setFloatingLabelColor(.lightGray, for: MDCTextControlState.editing)
}
or add constants to the leftAnchor and rightAnchor.
func textFields() {
let nameField = MDCFilledTextField()
nameField.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(nameField)
NSLayoutConstraint.activate([
nameField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
nameField.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
nameField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10),
nameField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10)
])
nameField.placeholder = "Name"
nameField.label.text = "Name"
nameField.setFloatingLabelColor(.lightGray, for: MDCTextControlState.editing)
}

Horizontal scrolling collection view partially hiding first cell content on initial load

I have a UIView and inside that, I have added a UILabel and UICollectionView. The UICollectionView scrolls horizontally. But the issue is that when I run the app, the UICollectionView offset is set in such a way that the first cell is partly hidden. If I scroll to the right then I can see the contents of the first cell. But when I let go it bounces back to its original hidden state.
As you can see here the first cell has 2 UIViews but only the second one is visible.
When I scroll right, this is how it looks:
The, I... 10, is the cell that is getting hidden. I have added the elements programmatically, so could be a constraint issue. But I can't zero down on what could be causing it.
Here's my UICollectionViewCell:
class UserCountryCell: UICollectionViewCell {
let countryNameLabel: UILabel
let countryUserCountLabel: UILabel
override init(frame: CGRect) {
countryNameLabel = UILabel()
countryUserCountLabel = UILabel()
super.init(frame: frame)
self.addSubview(countryNameLabel)
countryNameLabel.translatesAutoresizingMaskIntoConstraints = false
countryNameLabel.font = UIFont.boldSystemFont(ofSize: 13)
countryNameLabel.textColor = .white
self.addSubview(countryUserCountLabel)
countryUserCountLabel.translatesAutoresizingMaskIntoConstraints = false
countryUserCountLabel.font = UIFont.systemFont(ofSize: 13)
countryUserCountLabel.textColor = .white
NSLayoutConstraint.activate([
countryNameLabel.trailingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5),
countryNameLabel.heightAnchor.constraint(equalToConstant: 30),
countryNameLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5),
countryNameLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 5),
// countryNameLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0),
countryNameLabel.widthAnchor.constraint(equalToConstant: 20),
countryUserCountLabel.leadingAnchor.constraint(equalTo: countryNameLabel.trailingAnchor, constant: 5),
countryUserCountLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5),
countryUserCountLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 5),
countryUserCountLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -5),
countryUserCountLabel.heightAnchor.constraint(equalToConstant: 30),
countryUserCountLabel.widthAnchor.constraint(equalToConstant: 40)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(countryName: String, countryUserCount: Int) {
countryNameLabel.text = countryName
countryUserCountLabel.text = String(countryUserCount)
}
}
OK - couple things...
As I said in my comment, add subviews and constraints to the cell's .contentView, not to the cell itself.
You do have a few mistakes in your constraints. You constrained the countryNameLabel.trailingAnchor to self.leadingAnchor ... that should be .leadingAnchor to .leadingAnchor.
Your .bottomAnchor constants should be negative.
If you want the labels' text to determine their widths, don't assign a .widthAnchor.
Try replacing your init with this:
override init(frame: CGRect) {
countryNameLabel = UILabel()
countryUserCountLabel = UILabel()
super.init(frame: frame)
contentView.addSubview(countryNameLabel)
countryNameLabel.translatesAutoresizingMaskIntoConstraints = false
countryNameLabel.font = UIFont.boldSystemFont(ofSize: 13)
countryNameLabel.textColor = .white
contentView.addSubview(countryUserCountLabel)
countryUserCountLabel.translatesAutoresizingMaskIntoConstraints = false
countryUserCountLabel.font = UIFont.systemFont(ofSize: 13)
countryUserCountLabel.textColor = .white
NSLayoutConstraint.activate([
// needs to be .leadingAnchor to .leadingAnchor
//countryNameLabel.trailingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5),
countryNameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5),
countryNameLabel.heightAnchor.constraint(equalToConstant: 30),
countryNameLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
countryNameLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
// if you want the label width to fit its text
// don't set the label's widthAnchor
//countryNameLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0),
//countryNameLabel.widthAnchor.constraint(equalToConstant: 20),
countryUserCountLabel.leadingAnchor.constraint(equalTo: countryNameLabel.trailingAnchor, constant: 5),
countryUserCountLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
countryUserCountLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
countryUserCountLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5),
countryUserCountLabel.heightAnchor.constraint(equalToConstant: 30),
// if you want the label width to fit its text
// don't set the label's widthAnchor
//countryUserCountLabel.widthAnchor.constraint(equalToConstant: 40)
])
}

layout with before and after margins with equalToSystemSpacingAfter

I’m trying to change some layouts I have to a number-less layout.
This is what I have for a segmented bar that should be inside a container view with something like this | - margin - segmented - margin -|
segmentedControl.leadingAnchor.constraint(equalToSystemSpacingAfter: margins.leadingAnchor, multiplier: 1),
segmentedControl.trailingAnchor.constraint(equalToSystemSpacingAfter: margins.trailingAnchor, multiplier: 1),
I know that the second line doesn’t make any sense, but I don’t see any equalToSystemSpacingBEFORE just after, and I’m not sure how to do it without having to rely only on layout propagation.
Basically, the leadingAchor works fine with this code, but the trailingAnchor (as the method name implies) adds the margin AFTER the trailing anchor, which is not what I want.
any ideas?
You can constrain the trailingAnchor of your "container" view relative to the trailingAnchor of your segmented control.
Here's a quick example which I believe gives you the layout you want:
class SysSpacingViewController: UIViewController {
let seg: UISegmentedControl = {
let v = UISegmentedControl(items: ["A", "B", "C"])
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let cView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .white
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemYellow
cView.addSubview(seg)
view.addSubview(cView)
let g = view.safeAreaLayoutGuide
let m = cView.layoutMarginsGuide
NSLayoutConstraint.activate([
cView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
cView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
cView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
cView.heightAnchor.constraint(equalToConstant: 70.0),
seg.leadingAnchor.constraint(equalToSystemSpacingAfter: m.leadingAnchor, multiplier: 1.0),
m.trailingAnchor.constraint(equalToSystemSpacingAfter: seg.trailingAnchor, multiplier: 1.0),
seg.centerYAnchor.constraint(equalTo: cView.centerYAnchor),
])
}
}
Result:
I think you can use this:
segmentedControl.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8).isActive = true
segmentedControl.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8).isActive = true
Please change the name of containerView and constants accordingly.

In Swift, programmatically creating UIView and adding controls to it and using auto layout, causes the controls to appear on the view's parent

I am trying to write a simple composite component for iOS in Swift 3. It consists of a UILabel followed by an UITextField laid out horizontally followed by a line under them. But What happens is the UILabel disappears, UITextField appears on the parent view and line also disappears.
My design in sketch
What it actually looks like in the Storyboard
My component's constraints in the view controller
My intention was to use Auto Layout, anchor the label to top and leading anchors of the view, anchor the textfield to top of the view and trailing anchor of the label with a constant, so they would appear side by side.
I did do a lot of research on this, one site that looked pretty close to what I wanted was https://www.raywenderlich.com/125718/coding-auto-layout, and I think I am following more or less the same approach.
I am doing something obviously wrong, but can't figure out what. Any help is much appreciated, I have been at this for a few days now.
import UIKit
#IBDesignable
class OTextEdit: UIView {
#IBInspectable var LabelText: String = "Label"
#IBInspectable var SecureText: Bool = false
#IBInspectable var Color: UIColor = UIColor.black
#IBInspectable var Text: String = "" {
didSet {
edit.text = Text
}
}
fileprivate let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 35))
fileprivate let edit = UITextField(frame: CGRect(x: 210, y: 0, width: 200, height: 35))
fileprivate let line: UIView = UIView()
override var intrinsicContentSize: CGSize {
return CGSize(width: 300, height: 100)
}
func setup() {
label.text = LabelText
label.textColor = Color
label.font = UIFont(name: "Avenir Next Condensed", size: 24)
edit.font = UIFont(name: "Avenir Next Condensed", size: 24)
edit.borderStyle = .roundedRect
edit.isSecureTextEntry = SecureText
line.backgroundColor = UIColor.white
self.addSubview(label)
self.addSubview(edit)
self.addSubview(line)
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
setup()
setupConstaints()
}
func setupConstaints() {
label.translatesAutoresizingMaskIntoConstraints = false
edit.translatesAutoresizingMaskIntoConstraints = false
line.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: -10).isActive = true
label.topAnchor.constraint(equalTo: topAnchor)
edit.leadingAnchor.constraint(equalTo: label.leadingAnchor, constant: 10).isActive = true
edit.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
edit.topAnchor.constraint(equalTo: self.topAnchor)
line.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
line.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
line.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
line.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 1.0).isActive = true
}
}
You haven't got a series of constraints top to bottom, so auto layout can't determine the content size of your object. You have tried to set this via the initrinsicContentSize but you shouldn't need to do this.
You also need to set a horizontal hugging priority for your label to let auto layout know that you want the text field to expand:
I removed your override of intrinsicContentSize and changed your constraints to:
Constrain the bottom of the label to the top of the line
Constrain the bottom of the line to the bottom of the superview
Constrain the baseline of the label to the baseline of the text field
Remove the constraint between the top of the text field and the superview
Set the horizontal hugging priority of the label.
func setupConstraints() {
label.translatesAutoresizingMaskIntoConstraints = false
edit.translatesAutoresizingMaskIntoConstraints = false
line.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
label.topAnchor.constraint(equalTo: topAnchor)
label.bottomAnchor.constraint(equalTo: line.topAnchor, constant: -8).isActive = true
edit.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 10).isActive = true
edit.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
edit.firstBaselineAnchor.constraint(equalTo: label.firstBaselineAnchor).isActive = true
line.heightAnchor.constraint(equalToConstant: 2.0).isActive = true
line.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
line.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
line.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 1.0).isActive = true
line.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
I think it is pretty close to what you are after.

Resources