Why UITextView won't appear? - swift

I have a custom tableView Cell, I can't figure out why my UITextView won't show up.
This is my UITextView:
fileprivate let notificationBody: UITextView = {
let text = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
text.translatesAutoresizingMaskIntoConstraints = false
text.backgroundColor = UIColor.appWhite
text.font = UIFont.preferredFont(forTextStyle: .headline)
text.isScrollEnabled = true
text.isEditable = false
text.text = "hjfhsdjfdsfhjksdfhksdjhkfsdjhfshjdfahsdjfdsjklfjsdkfjksdlfjkdsfjklsdlkjfsdjklfsdjklfsdjklfjkldsfjklsdfkjldskjfsdlkjfsdklfjlkdsjflksdajflkdsjflksdjflksdajflksdajflsdkjflsdkjflsdkjflsdkjflsdjflsdjflsdjfsdlkjfslkd"
text.textAlignment = NSTextAlignment.natural
return text
}()
this is how I set it:
fileprivate func setupNotificationBody(){
addSubview(notificationBody)
NSLayoutConstraint.activate([
notificationBody.topAnchor.constraint(equalTo: notificationTitle.bottomAnchor, constant: 5),
notificationBody.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5),
notificationBody.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -5),
notificationBody.bottomAnchor.constraint(equalTo: self.dismissNotificationButton.topAnchor, constant: -5)
])
}
And ofcourse I called setupNotificationBody in Init.
I also have in this cell another button and a uilabel which show up correctly.

It looks like you need your cell to have dynamic height. In this case, you should set the property isScrollEnabled in your UITextView to false, so the UITextView will be able to calculate it's own height.
Also, remember to set the cell height to UITableView.automaticDimension in your UITableViewDelegate.

Related

How to change position of clear button in UISearchBar?

I want to change the position of clear button in UISearchBar
I'm customizing the search bar according to some design issues. I make all of the changes by reaching the UITextField inside the UISearchBar. With the clearButtonRect i can get the rectange but i can not change.
if let searchTextField = value(forKey: "searchField") as? UITextField {
searchTextField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
searchTextField.heightAnchor.constraint(equalToConstant: CGFloat(height)),
searchTextField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
searchTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
searchTextField.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0)
])
searchTextField.clipsToBounds = true
searchTextField.font = UIFont.regularDMSans(of: 17)
searchTextField.textColor = .textLight
searchTextField.layer.cornerRadius = 20
searchTextField.layer.borderWidth = 2.0
searchTextField.layer.borderColor = UIColor.createEventDivider.cgColor
if !shouldShowSearchIcon {
setImage(UIImage(), for: .search, state: .normal)
}
let offset = UIOffset(horizontal: 13, vertical: 0)
setPositionAdjustment(offset, for: .search)
}
the button with x on the right
let offset = UIOffset(horizontal: 13, vertical: 0)
setPositionAdjustment(offset, for: .clear)

The UI search bar disappears when clicked( possibly NSLayoutConstraint issue)

A quick question, for what should've been an easy implementation.
Im trying to implement a UISearchcontroller and the UIsearchbar property when trying to customize it and set constraints behaves properly appears perfect but the minute i click on the search bar it resets its constraints to nil(guessing based on visual debugger).
Before clicking
and here is the second image which shows what happens when clicked
After clicking
Ive been trying to do this for a day now.
Context: My Main VC is a collection view and another button.
below is the search view specific code, I tried isolating the issue in a playground file and noticed issue starts when i add constraints to it.
var searchController:UISearchController!
private func setupSearchView(){
let viewController = UISearchController(searchResultsController: nil)
viewController.delegate = self
let bar = viewController.searchBar
bar.delegate = self
bar.searchBarStyle = .minimal
bar.translatesAutoresizingMaskIntoConstraints=false
bar.searchTextField.layer.cornerRadius = 20
bar.searchTextField.textColor = .darkGray
bar.searchTextField.backgroundColor = .white
bar.showsCancelButton = false
bar.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
bar.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
bar.layer.shadowOpacity = 1.0
bar.layer.shadowRadius = 0.0
bar.layer.masksToBounds = false
guard let customFont = UIFont(name: "Poppins-SemiBold", size: 14.0) else {
fatalError("""
Failed to load the "CustomFont-Light" font.
Make sure the font file is included in the project and the font name is spelled correctly.
"""
)}
bar.searchTextField.font=customFont
self.searchController = viewController
self.view.addSubview(bar)
bar.isHidden = true
}
func setupContstraints() {
//NSLayoutConstrainst
let searchBar:UISearchBar=searchController!.searchBar
NSLayoutConstraint.activate([
searchButton!.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
searchButton!.topAnchor.constraint(equalTo: view.topAnchor, constant: 30),
searchButton!.widthAnchor.constraint(equalToConstant: 50),
searchButton!.heightAnchor.constraint(equalToConstant: 50),
//search bar
searchBar.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
searchBar.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30),
searchBar.widthAnchor.constraint(equalToConstant: 170.0),
searchBar.heightAnchor.constraint(equalToConstant: 50.0)]
)
Update:
When i gave the search bar fixed width and height(not ideal for different device size) it now appears with the width and height but doesn't obey the top anchor constraint.
See current image
also updated the snippet with current constraints
Give a fixed width and height value for your "SearchBar" object. It will probably be fixed.
It may take up as much width as the cursor when clicked.
Comment out or delete the 2 lines below while giving a fixed height and width for the searchBar.
searchBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 50),
searchBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -100)
Rid of the UISearchController and use a UISearchBar instead.
let searchBar = UISearchBar()
let clearButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .gray
setupSearchView()
}
private func setupSearchView(){
searchBar.searchBarStyle = .minimal
searchBar.translatesAutoresizingMaskIntoConstraints=false
searchBar.searchTextField.layer.cornerRadius = 20
searchBar.searchTextField.textColor = .darkGray
searchBar.searchTextField.backgroundColor = .white
searchBar.showsCancelButton = false
searchBar.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
searchBar.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
searchBar.layer.shadowOpacity = 1.0
searchBar.layer.shadowRadius = 0.0
searchBar.layer.masksToBounds = false
// guard let customFont = UIFont(name: "Poppins-SemiBold", size: 14.0) else {
// fatalError("""
// Failed to load the "CustomFont-Light" font.
// Make sure the font file is included in the project and the font name is spelled correctly.
// """
// )}
// bar.searchTextField.font=customFont
// set your search clear button
clearButton.setImage(UIImage(systemName: "multiply.circle.fill"), for: .normal)
clearButton.tintColor = .red
let searchStack = UIStackView(arrangedSubviews: [searchBar, clearButton])
searchStack.axis = .horizontal
searchStack.distribution = .fill
searchStack.alignment = .fill
searchStack.spacing = 16
searchStack.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(searchStack)
// bar.isHidden = true
NSLayoutConstraint.activate([
clearButton.heightAnchor.constraint(equalTo: clearButton.widthAnchor),
searchStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30),
searchStack.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 30),
searchStack.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -30),
searchStack.heightAnchor.constraint(equalToConstant: 50)
])
}

iOS how to create a UIView border with label on top of that

I have to add label on top of UIView border, how do I achieve that using beizer path by drawing only part of the border on view
This can be realized by implementing a BorderLabelView where a contentView and a label is added. To the contentView a textField is added which is positioned vertically centered to its parent.
The label is positioned relatively to the top of the parent but moved up by a negative constant value.
An extra contentView is used (instead of the BorderLabelView itself) to set the border with rounded corners, so that masksToBounds can be set without masking the part of the label that sticks up a little bit.
For the label some leading and trailing space is needed. That is why UILabel is subclassed so that intrinsicContentSize can be reset.
This is a working example implementation:
import UIKit
class PaddedLabel: UILabel {
override var intrinsicContentSize: CGSize {
CGSize(width: super.intrinsicContentSize.width + 20, height: super.intrinsicContentSize.height)
}
}
class BorderLabelView: UIView {
convenience init(labelName: String, textContent: String) {
self.init()
let contentView = UIView()
contentView.backgroundColor = .white
contentView.layer.borderWidth = 0.5
contentView.layer.borderColor = UIColor.lightGray.cgColor
contentView.layer.cornerRadius = 10;
contentView.layer.masksToBounds = true;
let textField = UITextField()
textField.textColor = .black
textField.font = UIFont.systemFont(ofSize: 22.0)
textField.text = textContent
contentView.addSubview(textField)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 25).isActive = true
textField.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
contentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
contentView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
let label = PaddedLabel()
label.text = labelName
label.backgroundColor = .white
label.textColor = UIColor.lightGray
label.textAlignment = .center
addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: topAnchor, constant: -10).isActive = true
label.leftAnchor.constraint(equalTo: leftAnchor, constant: 15).isActive = true
}
}
The view can be used by calling the initializer
BorderLabelView(labelName: "User name", textContent: "Sanjay SK")
This is an example implementation for a UIViewController:
import UIKit
class BorderLabelController: UIViewController {
override func viewDidLoad() {
view.backgroundColor = .white
let borderLabelView = BorderLabelView(labelName: "User name", textContent: "Sanjay SK")
view.addSubview(borderLabelView)
borderLabelView.translatesAutoresizingMaskIntoConstraints = false
borderLabelView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
borderLabelView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
borderLabelView.heightAnchor.constraint(equalToConstant: 100).isActive = true
borderLabelView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.size.width - 40).isActive = true
}
}
Create a border and rounded UIView.. Inside that view you can add label or UITextField whose text is "Sanjay SK" with respect to given sample image
Give that view border color , border width and corer radious.. then take a UILabel with background color white and add it over that bordered UIView ... will give you same look and feel ... hope it will help you

UIView resize to fit labels inside of it

I have a UIView that I'm appending into a stack view on my main page of my app
This is the class of my view:
class MyCustomView: UIView {
public let leftLabel: UILabel = UILabel(frame: .zero)
public let rightLabel: UILabel = UILabel(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(leftLabel)
addSubview(rightLabel)
leftLabel.translatesAutoresizingMaskIntoConstraints = false
rightLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
leftLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.4),
leftLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
leftLabel.topAnchor.constraint(equalTo: topAnchor),
leftLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
rightLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.6),
rightLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
rightLabel.topAnchor.constraint(equalTo: topAnchor),
rightLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
])
leftLabel.text = "Short string"
rightLabel.text = "Short string too"
}
}
And I append to my main stack view with:
let myCustomView = MyCustomView(frame: .zero)
stackView.addArrangedSubview(myCustomView)
This loads in my label's correctly and resizes everything as I'd want.
However, in my main class, I am updating myCustomView.rightLabel.text = <New Way Longer Text That Takes 2 Lines Instead of One>
The text is updating properly, but my myCustomView size is not resizing, so part of the text is just being cut-off
I have tried following other answers on here, but none of them seem to work for me.
Am I missing something small in order to force the resize of the customView to fit the label inside of it?
Thank you in advance
Your code does not show that you set the .numberOfLines in the label(s) to 0 to allow for multi-line labels.
Adding only that, should allow your labels to grow in height and to expand your custom view. However... that will also make both labels expand to the size of the tallest label, resulting in the text of the "shorter" label being vertically centered (I added background colors to make it easy to see the frames / bounds of the views):
If you constrain the Bottom of your custom view to the Bottom of each label at greaterThanOrEqualTo you can keep the labels "top-aligned":
You can run this code directly in a Playground page to see the results:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyCustomView: UIView {
public let leftLabel: UILabel = UILabel(frame: .zero)
public let rightLabel: UILabel = UILabel(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(leftLabel)
addSubview(rightLabel)
// background colors so we can see the view frames
backgroundColor = .cyan
leftLabel.backgroundColor = .yellow
rightLabel.backgroundColor = .green
// we want multi-line labels
leftLabel.numberOfLines = 0
rightLabel.numberOfLines = 0
// use auto-layout
leftLabel.translatesAutoresizingMaskIntoConstraints = false
rightLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// constrain to top
leftLabel.topAnchor.constraint(equalTo: topAnchor),
// constrain to left
leftLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
// constrain width = 40%
leftLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.4),
// constrain to top
rightLabel.topAnchor.constraint(equalTo: topAnchor),
// constrain to right
rightLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
// constrain width = 60%
rightLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.6),
// constrain bottom of view (self) to >= 0 from bottom of leftLabel
bottomAnchor.constraint(greaterThanOrEqualTo: leftLabel.bottomAnchor, constant: 0.0),
// constrain bottom of view (self) to >= 0 from bottom of rightLabel
bottomAnchor.constraint(greaterThanOrEqualTo: rightLabel.bottomAnchor, constant: 0.0),
])
leftLabel.text = "Short string"
rightLabel.text = "Short string too"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class MyViewController : UIViewController {
var theButton: UIButton = {
let b = UIButton()
b.setTitle("Tap Me", for: .normal)
b.translatesAutoresizingMaskIntoConstraints = false
b.backgroundColor = .red
return b
}()
var theStackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.spacing = 8
v.distribution = .equalSpacing
return v
}()
var myView = MyCustomView()
// on button tap, change the text in the label(s)
#objc func didTap(_ sender: Any?) -> Void {
myView.leftLabel.text = "Short string with\nA\nB\nC\nD\nE"
myView.rightLabel.text = "Short string too\nA\nB"
}
override func loadView() {
let view = UIView()
self.view = view
view.backgroundColor = .white
view.addSubview(theButton)
// constrain button to Top: 32 and centerX
NSLayoutConstraint.activate([
theButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 32.0),
theButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),
])
view.addSubview(theStackView)
// constrain stack view to Top: 100 and Leading/Trailing" 0
// no Bottom or Height constraint
NSLayoutConstraint.activate([
theStackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100.0),
theStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0),
theStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0),
])
theStackView.addArrangedSubview(myView)
// add an action for the button tap
theButton.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

Why doesn't Autolayout change a views frame

I created a view in a func of its superview
let black = NSView(frame: NSRect(x: 0, y: 0, width: 10, height: 10))
black.translatesAutoresizingMaskIntoConstraints = false
black.wantsLayer = true
black.layer?.backgroundColor = NSColor.black.cgColor
self.addSubview(black)
black.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -15).isActive = true
black.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 15).isActive = true
black.heightAnchor.constraint(equalToConstant: 115).isActive = true
black.widthAnchor.constraint(equalToConstant: 115).isActive = true
print ("origin (\(black.frame.origin.x),\(black.frame.origin.y)) size (\(black.frame.size.width),\(black.frame.size.height)) ")
The output is origin(0,0), size(10,10), these are the values the view was created with.
On screen the black view is positioned as expected origin:(15,15) size:(115,115).
Why is the frame not updated?
After setting the constraints you can update the frame of your view calling the same of layoutIfNeeded function for Cocoa:
black.layoutSubtreeIfNeeded()