Hi i have created a view programmatically. With in that i have added label and text field. But When i tap on text field, text field is not working. It is not even call its delegate methods. Please help on this.
in for Loop i am calling this return method for creating Text field
widgetsView.addSubview(createTextFieldForDropDown(entity,ival:i,ypos: posY))
//Method to create view with text field and lable
func createTextFieldForDropDown(entity:ListingCategoryFeaturesEntity,ival:Int,ypos:CGFloat) -> UIView
{
var posY = ypos
var posX = CGFloat(0)
let width = (SCREEN_WIDTH/2)-15
var height = CGFloat(40)
let viewRadio = UIView()
viewRadio.frame = CGRectMake(posX, posY, width, height)
viewRadio.backgroundColor = UIColor.greenColor()
height = 40
posY = 0
let lblTitle = UILabel()
lblTitle.frame = CGRectMake(posX, posY, width, height)
lblTitle.text = entity.strDisplayName
lblTitle.backgroundColor = UIColor.redColor()
lblTitle.font = GRAPHICS.FONT_REGULAR(16)
viewRadio.addSubview(lblTitle)
let tag = 9000
posX = lblTitle.frame.maxX+10
var textField = UITextField()
textField.frame = CGRectMake(posX, posY, width, height)
textField = returnTextFieldsProperties(textField, placeHolderText: "", tagValue: tag+ival)
textField.backgroundColor = UIColor.blueColor()
textField.becomeFirstResponder()
viewRadio.addSubview(textField)
return viewRadio
}
//Method to retrun text field properties
func returnTextFieldsProperties(textField : UITextField ,placeHolderText : String ,tagValue : Int) -> UITextField
{
textField.attributedPlaceholder = NSAttributedString(string:placeHolderText,
attributes:[NSForegroundColorAttributeName: UIColorFromRGB(colorLightGray, alpha: 1.0)])
textField.font = GRAPHICS.FONT_REGULAR(14)
textField.textAlignment = NSTextAlignment.Left
textField.textColor = UIColor.blackColor()
textField.delegate = self
textField.userInteractionEnabled = true
textField.returnKeyType = UIReturnKeyType.Next
let view_left = UIView()
view_left.frame = CGRectMake(20,0,10,textField.frameHeight)
textField.leftView = view_left
textField.leftViewMode = UITextFieldViewMode.Always
textField.borderStyle = UITextBorderStyle.RoundedRect
textField.backgroundColor = UIColor.clearColor()
textField.autocorrectionType = .No
textField.tag = tagValue
return textField
}
Try to remove:
textField.becomeFirstResponder()
This may be the problem since you have all your text fields marked with that, but what you want, I assume, is that only the text field that you tapped should be a first responder.
The problem is that your textField is not within the bounds of its superview viewRadio. Make the viewRadio wide enough to hold both the label and the textView:
Change:
viewRadio.frame = CGRectMake(posX, posY, width, height)
to:
viewRadio.frame = CGRectMake(posX, posY, SCREEN_WIDTH, height)
I think you did not set the delegate method, check the below used in your project,
import UIKit
class ViewController: UIViewController, UITextFieldDelegate
if you create the textfield initially set the delegate method is,
var textField = UITextField()
textField.frame = CGRectMake(posX, posY, width, height)
textField = returnTextFieldsProperties(textField, placeHolderText: "", tagValue: tag+ival)
**textField.delegate = self**
textField.backgroundColor = UIColor.blueColor()
viewRadio.addSubview(textField)
hope its helpful
Simple answer, just write delegate method and set delegate of UITextField in storyboard or manually in viewDidLoad
Write something like this, And It will work Perfectly.
extension LoginVC : UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Related
I'm building a scrolling feed in my app with data grabbed from a database (firebase). I'm not very experienced in Swift as most of the stuff I do is web design. What I'm looking for is a good way to size the height of my UIViews. Here is what I currently have (fixed height):
Here's my code UIView class:
class eventView: UIView {
let eventDate : UILabel = {
let eventDate = UILabel()
eventDate.translatesAutoresizingMaskIntoConstraints = false
eventDate.numberOfLines = 0
eventDate.textAlignment = .center
return eventDate
}()
let eventTitle : UILabel = {
Same thing as eventDate
}()
let eventDesc : UILabel = {
same thing as eventDate
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.lightGray
self.layer.cornerRadius = 10
self.addSubview(eventDate)
eventDate.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
eventDate.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
self.addSubview(eventTitle)
eventTitle.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
eventTitle.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
eventTitle.topAnchor.constraint(equalTo: eventDate.bottomAnchor).isActive = true
self.addSubview(eventDesc)
eventDesc.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
eventDesc.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
eventDesc.topAnchor.constraint(equalTo: eventTitle.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is my for list that displays these UIViews:
var i = 0
for data in self.eventViewData {
let view = eventView(frame: CGRect(x: 0, y: ( CGFloat(170 * i)), width: self.scrollView.frame.width - 20, height: CGFloat(150)))
view.center.x = self.scrollView.center.x
view.eventDate.text = data.date
view.eventTitle.text = data.title
view.eventDesc.text = data.description
self.scrollView.addSubview(view)
i += 1
}
I usually am using HTML div's and such so I'm having a hard time figuring out how to style these. Any information or links to tutorials on how to programmatically adjust constraints to the UILabels in my eventViews are also appreciated.
How to calculate the desired height seems to be the question. While there are a lot of ways to do this one approach would be something like this:
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
let font = UIFont(name: "Helvetica", size: 20.0)
var height = heightForView("This is just a load of text", font: font, width: 100.0)
// apply height to desired view
I prefer to put the heightForView function in an extension myself but it isn't required.
I assumed you're using table view, why not do dynamic height? Good reference https://www.raywenderlich.com/1067-self-sizing-table-view-cells
In essense, you use auto layout to define your top and bottom constraint accordingly for every element in your cell, and your table view delegation/data source method for heightforrow and estimatedheightforrow, return UITableViewAutomaticDimension
I have a UITextField which spans the width of my view. I'd like to add a small image that sits directly to the left-most character entered in my UITextView.
Is that possible? From the docs, it looks like .leftView sits to the left-most position of the UITextField rather than directly to the left of the text as the user types.
Thanks
Write Below code to add left image in TextField
Class CustomTextField : UITextField {
/// A UIImage value that set LeftImage to the UItextfield
#IBInspectable open var leftImage:UIImage? {
didSet {
if (leftImage != nil) {
self.leftImage(leftImage!)
}
}
}
fileprivate func leftImage(_ image: UIImage)
{
rightPadding()
let icn : UIImage = image
let imageView = UIImageView(image: icn)
imageView.frame = CGRect(x: 0, y: 0, width: icn.size.width + 20, height: icn.size.height)
imageView.contentMode = UIViewContentMode.center
self.leftViewMode = UITextFieldViewMode.always
let view = UIView(frame: CGRect(x: 0, y: 0, width: imageView.frame.size.width, height: imageView.frame.size.height))
view.addSubview(imageView)
self.leftView = view
}
/// Give right padding to UITextField
fileprivate func rightPadding() {
let paddingRight = UIView(frame: CGRect(x: 0, y: 5, width: 5, height: 5))
self.rightView = paddingRight
self.rightViewMode = UITextFieldViewMode.always
}
}
Then after in storyboard select textfield give class name "CustomTextField" and then see in your attribute inspector select your image.
I hope it will help you.
Yes, you are correct about the leftView property of the UITextField - as far as I know it stays to the left of the textfield.
I would do it using autolayout and a separate UIImageView anchored to the right side of the textField and I would dynamically change the constant of the constraint to move it with text. You can determine the current width using answers in this SO Question.
I've created a simple example you can use as your starting point:
import UIKit
class CustomVC: UIViewController {
let textField = UITextField()
// use your image here
let imageView = UIImageView(image: #imageLiteral(resourceName: "your_image_here"))
var imagePositionFromRight: NSLayoutConstraint!
let imageOffset: CGFloat = CGFloat(4)
override func loadView() {
self.view = UIView()
view.backgroundColor = UIColor.lightGray
view.addSubview(textField)
view.addSubview(imageView)
// if alignment is .left, you can just use leftView property
textField.textAlignment = .right
textField.backgroundColor = UIColor.white
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
textField.translatesAutoresizingMaskIntoConstraints = false
imagePositionFromRight = textField.rightAnchor.constraint(equalTo: imageView.rightAnchor, constant: imageOffset)
NSLayoutConstraint.activate([
textField.rightAnchor.constraint(equalTo: view.rightAnchor),
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textField.leftAnchor.constraint(equalTo: view.leftAnchor),
imageView.topAnchor.constraint(equalTo: textField.topAnchor),
imageView.bottomAnchor.constraint(equalTo: textField.bottomAnchor),
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor),
imagePositionFromRight,
])
textField.delegate = self
}
}
extension CustomVC: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let proposedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) ?? ""
textField.text = proposedString
let width = textField.attributedText?.size().width
imagePositionFromRight.constant = (width ?? 0) + imageOffset
// returning false since we updated text above manually
return false
}
}
P.S.: Consider adding the image view as a subview of the textField and setting textField.clipsToBounds = true, if the image view never exceeds the textField.
I am using Swift 3, Xcode 8.2.
I've been able to create a label to cover the empty table view cells when there are none to display.
My code is below and it is located in the subclass of UITableViewController.
override func numberOfSections(in tableView: UITableView) -> Int {
// if there are scans to display...
if items.count > 0 {
tableView.backgroundView = nil
tableView.separatorStyle = .singleLine
return 1
}
else { // otherwise, return 0, remove cell lines, and display a Label
let rect = CGRect(x: 0,
y: 0,
width: tableView.bounds.size.width,
height: tableView.bounds.size.height)
let noScanLabel: UILabel = UILabel(frame: rect)
noScanLabel.text = "No Scans"
noScanLabel.textColor = UIColor.gray
noScanLabel.font = UIFont.boldSystemFont(ofSize: 24)
noScanLabel.textAlignment = NSTextAlignment.center
tableView.backgroundView = noScanLabel
tableView.separatorStyle = .none
return 0
}
}
Here is the result.
Looks fine. But how, do I make it such that I include another line of text with a downward arrow pointing at the raised center button. Something like "Click here to start a scan"?
I've tried adding new line characters to the noScanLabel.text field but that didn't work out. Any pointers in the right direction would be helpful.
The simple solution is to set numberOfLines to 0 on noScanLabel. This way, the new lines will show.
let noScanLabel: UILabel = UILabel(frame: rect)
noScanLabel.text = "No Scans"
noScanLabel.textColor = UIColor.gray
noScanLabel.font = UIFont.boldSystemFont(ofSize: 24)
noScanLabel.numberOfLines = 0
noScanLabel.textAlignment = NSTextAlignment.center
Note than in such cases, I would recommend, for better maintainability, to actually remove the TableView from the UIViewController (hence not inherit from UITableViewController) and replace it with an empty view when you detect no scans are available. This will make each state more independent of each other and make maintenance easier.
There are a few ways achieve your goal. There is a well known library called DZNEmptyDataSet for handling empty tableviews and collectionviews . https://github.com/dzenbot/DZNEmptyDataSet
The other way would be to create a uiview with your specified rect and then add two labels to that uiview. One would be your noScanLabel and the other would be a label or image containing your arrow. You can set the layout constraints as required so that the arrow appears pointing down.
This code seems to work well. Change constraints if needed
let rect = CGRect(x: 0, y: 0, width: tableview.bounds.size.width, height: tableview.bounds.size.height)
let noDataView = UIView(frame: rect)
let noScanLabel = UILabel()
noScanLabel.text = "No Scans"
noScanLabel.textColor = UIColor.gray
noScanLabel.font = UIFont.boldSystemFont(ofSize: 24)
noScanLabel.textAlignment = NSTextAlignment.center
let arrowLabel = UILabel()
arrowLabel.text = "Add Arrow Image to this label"
arrowLabel.textColor = UIColor.gray
arrowLabel.font = UIFont.boldSystemFont(ofSize: 24)
arrowLabel.textAlignment = NSTextAlignment.center
noScanLabel.widthAnchor.constraint(equalToConstant: 100)
arrowLabel.widthAnchor.constraint(equalToConstant: 50)
noDataView.addSubview(noScanLabel)
noDataView.addSubview(arrowLabel)
arrowLabel.translatesAutoresizingMaskIntoConstraints = false
noDataView.translatesAutoresizingMaskIntoConstraints = false
noScanLabel.translatesAutoresizingMaskIntoConstraints = false
self.tableview.addSubview(noDataView)
noDataView.isHidden = false
noDataView.centerXAnchor.constraint(equalTo: self.tableview.centerXAnchor).isActive = true
noDataView.centerYAnchor.constraint(equalTo: self.tableview.centerYAnchor).isActive = true
noScanLabel.centerXAnchor.constraint(equalTo: noDataView.centerXAnchor).isActive = true
noScanLabel.topAnchor.constraint(equalTo: noDataView.centerYAnchor).isActive = true
arrowLabel.centerXAnchor.constraint(equalTo: noDataView.centerXAnchor).isActive = true
arrowLabel.topAnchor.constraint(equalTo: noScanLabel.bottomAnchor).isActive = true
The other option is to set number of lines to zero as mentioned already
noScanLabel.numberLines = 0
You can take UIView and add your all UILabel and arrow Image on UIView and then assign that UIView to backgroundView of TableView.
Like this.
override func numberOfSections(in tableView: UITableView) -> Int {
// if there are scans to display...
if items.count > 0 {
tableView.backgroundView = nil
tableView.separatorStyle = .singleLine
return 1
}
else { // otherwise, return 0, remove cell lines, and display a Label
let rect = CGRect(x: 0,
y: 0,
width: tableView.bounds.size.width,
height: tableView.bounds.size.height)
let messageBaseView = UIView(frame: rect)
//Add your first label..
let noScanLabel: UILabel = UILabel()
noScanLabel.text = "No Scans"
noScanLabel.textColor = UIColor.gray
noScanLabel.font = UIFont.boldSystemFont(ofSize: 24)
noScanLabel.textAlignment = NSTextAlignment.center
messageBaseView.addSubView(noScanLabel)
//Add your second label.. and your arrow image here on messageBaseView
//Assign messageBaseView to backgroundView of tableView
tableView.backgroundView = messageBaseView
tableView.separatorStyle = .none
return 0
}
}
Is it possible to adjust the font size of the navigation bar's title to fit the text?
You can create a UILabel and set it to UINavigationItem's titleView. See Apple doc: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationItem_Class/#//apple_ref/occ/instp/UINavigationItem/titleView
For the created UILabel, you can set the adjustsFontSizeToFitWidth & minimumScaleFactor properties to let it fit the title. Doc:
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UILabel_Class/#//apple_ref/occ/instp/UILabel/adjustsFontSizeToFitWidth
Some codes:
- (void)setMyTitle:(NSString *)title
{
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.navigationController.view.bounds.size.width - 100, 44)];
titleLabel.text = title;
titleLabel.font = [UIFont systemFontOfSize:16];
titleLabel.textColor = ...
...
self.navigationItem.titleView = titleLabel;
}
Try the following in viewDidLoad:
NSDictionary *attributes = #{ NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-Bold" size:14] };
[self.navigationController.navigationBar setTitleTextAttributes:attributes];
NOTE: The downside to this solution is that you have to know the font size up front and set it manually. I'm not sure if you can set the navigation bar's title label to automatically change the font size to fit the text.
EDIT:
Turns out you can set the navigation bar's label to resize the font size dynamically
Swift 5
private var isFirst = true
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard isFirst else {
return
}
isFirst = false
// Adjust Navigation Title by text
if let navigationController = navigationController {
let bar = navigationController.navigationBar
var minX: CGFloat = 0
var maxX: CGFloat = bar.bounds.width
if let lastLeft = navigationItem.leftBarButtonItems?.last, let leftView = lastLeft.view, let buttonBarStackViewFrame = leftView.superview?.frame {
minX = buttonBarStackViewFrame.maxX
}
if let firstRight = navigationItem.rightBarButtonItems?.first, let rightView = firstRight.view, let buttonBarStackViewFrame = rightView.superview?.frame {
maxX = buttonBarStackViewFrame.minX
}
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: maxX - minX, height: bar.bounds.height))
titleLabel.text = LocStr(.favorite_master_title)
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.3
titleLabel.textColor = UIColor.white
titleLabel.textAlignment = .center
if UIDevice.current.modelName.contains(PLUS) {
titleLabel.font = UIFont(name: GENERAL_FONT_NAME, size: PLUS_NAVIGATION_BAR_TITLE_FONT)!
} else {
titleLabel.font = UIFont(name: GENERAL_FONT_NAME, size: GENERAL_NAVIGATION_BAR_TITLE_FONT)!
}
navigationItem.titleView = titleLabel
}
}
with a Extension
extension UIBarButtonItem {
var view: UIView? {
return value(forKey: "view") as? UIView
}
}
I have the following view which contains a UILabel:
class MyView : UIView {
func viewDidLoad() {
self.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
bottomView = UIView(frame: CGRectMake(self.bounds.origin.x, self.bounds.origin.y + self.imageView!.bounds.size.width, self.bounds.size.width, self.bounds.size.height - self.imageView!.bounds.size.height))
// bottomView frame calculation is: (0.0, 355.0, 355.0, 130.0)
bottomView?.backgroundColor = UIColor.greenColor()
bottomView?.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomView?.clipsToBounds = true
self.addSubview(self.bottomView!)
var descriptionRect: CGRect = CGRectInset(self.bottomView!.bounds, leftRightInset, 20/2)
let descriptionLabel = UILabel()
descriptionLabel.numberOfLines = 3
descriptionLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth
descriptionLabel.font = UIFont(name: MGFont.helvetica, size: 22)
descriptionLabel.textColor = UIColor.whiteColor()
descriptionLabel.textAlignment = NSTextAlignment.Left
descriptionLabel.backgroundColor = UIColor.blueColor()
var paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1.0
paragraphStyle.lineBreakMode = NSLineBreakMode.ByTruncatingTail
let attributes = [NSParagraphStyleAttributeName : paragraphStyle]
descriptionLabel.attributedText = NSAttributedString(string: previewCard.title, attributes:attributes)
bottomView?.addSubview(descriptionLabel)
descriptionLabel.bounds = descriptionRect
descriptionLabel.sizeToFit()
descriptionLabel.center = CGPointMake(bottomView!.bounds.width/2, bottomView!.bounds.height/2 - hotelNameLableHeight/2)
}
}
The height of the bottomView should always be fixed.
MyView is resized during runtime. This means that the green bottom view also increases in size.
Here is the result when the label has two and three lines:
It appears that the UILabel resizes its super view.
Note that I do not use AutoLayout.
override func layoutSubviews() {
super.layoutSubviews()
}
How can I prevent the UILabel from resizing its SuperView?
Edit: I also tried to comment bottomView?.clipsToBounds = true
Override setFrame: and setBounds: of the super view (subclass if they're plain UIViews), add breakpoints, and see the stack trace to find out what's causing them to resize.
There is no need to set the autoResizingMask on the label, just set the frame and it will get automatically centered. And of course you can set the insets for the UILabel accordingly. I've add below testing code FYI:
override func viewDidLayoutSubviews() {
addTestView(CGRectMake(0, 200, view.bounds.width, 50), labelStr: "I am a short testing label")
addTestView(CGRectMake(0, 260, view.bounds.width, 50), labelStr: "I am a very longlonglonglonglonglonglong testing label")
addTestView(CGRectMake(0, 320, view.bounds.width, 50), labelStr: "I am a very longlonglonglonglonglonglonglonglonglonglonglong testing label. Will be truncated")
}
func addTestView(frame:CGRect, labelStr: String){
let bottomView = UIView(frame:frame)
bottomView.backgroundColor = UIColor.greenColor()
bottomView.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomView.clipsToBounds = true
view.addSubview(bottomView)
var label = UILabel(frame: bottomView.bounds)
label.textAlignment = NSTextAlignment.Left
label.numberOfLines = 0
label.text = labelStr
bottomView.addSubview(label)
}