I'm working on an app in swift. Currently, I'm working on the population of a table view with custom cells, see screenshot. However, right now I have the text set so that the title is exactly 2 lines and the summary is exactly 3 lines. By doing this, the text is sometimes truncated. Now, I want to set the priority for text in the title, so that if the title is truncated when it is 2 lines long I expand it to 3 lines and make the summary only 2 lines. I tried doing this with auto layout, but failed. Now I tried the following approach, according to this and this, but the function below also didn't seem to accurately determine if the text is truncated.
func isTruncated(label:UILabel) -> Bool {
let context = NSStringDrawingContext()
let text : NSAttributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : label.font])
let labelSize : CGSize = CGSize(width: label.frame.width, height: CGFloat.max)
let options : NSStringDrawingOptions = unsafeBitCast(NSStringDrawingOptions.UsesLineFragmentOrigin.rawValue | NSStringDrawingOptions.UsesFontLeading.rawValue, NSStringDrawingOptions.self)
let labelRect : CGRect = text.boundingRectWithSize(labelSize, options: options, context: context)
if Float(labelRect.height/label.font.lineHeight) > Float(label.numberOfLines) {
return true
} else {
return false
}
}
Can anybody help? How can I change my function to make this work? Or should work with different auto layout constraints and how?
Thanks so much!
EDIT:
this is my current code. Some auto layout is done is the storyboard, however the changing auto layout is done in code.
import UIKit
class FeedTableViewCell: UITableViewCell {
var thumbnailImage = UIImageView()
#IBOutlet var titleText: UILabel!
#IBOutlet var summaryText: UILabel!
#IBOutlet var sourceAndDateText: UILabel!
var imgTitleConst = NSLayoutConstraint()
var imgSummaryConst = NSLayoutConstraint()
var imgDetailConst = NSLayoutConstraint()
var titleConst = NSLayoutConstraint()
var summaryConst = NSLayoutConstraint()
var detailConst = NSLayoutConstraint()
var titleHeightConst = NSLayoutConstraint()
var summaryHeightConst = NSLayoutConstraint()
var imageRemoved = false
var titleConstAdd = false
override func awakeFromNib() {
super.awakeFromNib()
thumbnailImage.clipsToBounds = true
summaryText.clipsToBounds = true
titleText.clipsToBounds = true
sourceAndDateText.clipsToBounds = true
addImage()
}
func removeImage() {
if let viewToRemove = self.viewWithTag(123) {
imageRemoved = true
viewToRemove.removeFromSuperview()
self.contentView.removeConstraints([imgTitleConst, imgSummaryConst, imgDetailConst])
titleConst = NSLayoutConstraint(item: self.titleText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
summaryConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
detailConst = NSLayoutConstraint(item: sourceAndDateText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
self.contentView.addConstraints([titleConst, detailConst, summaryConst])
setNumberOfLines()
self.contentView.layoutSubviews()
}
}
func addImage() {
thumbnailImage.tag = 123
thumbnailImage.image = UIImage(named: "placeholder")
thumbnailImage.frame = CGRectMake(14, 12, 100, 100)
thumbnailImage.contentMode = UIViewContentMode.ScaleAspectFill
thumbnailImage.clipsToBounds = true
self.contentView.addSubview(thumbnailImage)
if imageRemoved {
self.contentView.removeConstraints([titleConst, summaryConst, detailConst])
}
var widthConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
var heightConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
var leftConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 14)
var topConst = NSLayoutConstraint(item: thumbnailImage, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 12)
imgTitleConst = NSLayoutConstraint(item: self.titleText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8)
imgSummaryConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8)
imgDetailConst = NSLayoutConstraint(item: sourceAndDateText, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.thumbnailImage, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 8)
self.contentView.addConstraints([widthConst, heightConst, leftConst, topConst, imgTitleConst, imgSummaryConst, imgDetailConst])
setNumberOfLines()
self.contentView.layoutSubviews()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setNumberOfLines() {
if titleConstAdd {
self.contentView.removeConstraints([titleHeightConst, summaryHeightConst])
}
if titleText.numberOfLines == 3 {
titleText.numberOfLines = 2
}
if countLabelLines(titleText) > 2 {
titleText.numberOfLines = 3
summaryText.numberOfLines = 2
println("adjusting label heigh to be taller")
titleHeightConst = NSLayoutConstraint(item: titleText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 51)
summaryHeightConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 32)
self.contentView.addConstraints([titleHeightConst, summaryHeightConst])
} else {
titleText.numberOfLines = 2
summaryText.numberOfLines = 3
titleHeightConst = NSLayoutConstraint(item: titleText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 36)
summaryHeightConst = NSLayoutConstraint(item: summaryText, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 47)
self.contentView.addConstraints([titleHeightConst, summaryHeightConst])
}
titleConstAdd = true
}
}
func countLabelLines(label:UILabel)->Int{
if let text = label.text{
// cast text to NSString so we can use sizeWithAttributes
var myText = text as NSString
//Set attributes
var attributes = [NSFontAttributeName : UIFont.boldSystemFontOfSize(14)]
//Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another
var labelSize = myText.boundingRectWithSize(CGSizeMake(label.bounds.width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil)
//Now we return the amount of lines using the ceil method
var lines = ceil(CGFloat(labelSize.height) / label.font.lineHeight)
println(labelSize.height)
println("\(lines)")
return Int(lines)
}
return 0
}
You can use the sizeWithAttributes method from NSString to get the number of lines your UILabel has. You will have to cast your label text to NSString first to use this method:
func countLabelLines(label:UILabel)->Int{
if let text = label.text{
// cast text to NSString so we can use sizeWithAttributes
var myText = text as NSString
//A Paragraph that we use to set the lineBreakMode.
var paragraph = NSMutableParagraphStyle()
//Set the lineBreakMode to wordWrapping
paragraph.lineBreakMode = NSLineBreakMode.ByWordWrapping
//Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another
var labelSize = myText.sizeWithAttributes([NSFontAttributeName : UIFont.systemFontOfSize(17), NSParagraphStyleAttributeName : paragraph.copy()])
//Now we return the amount of lines using the ceil method
var lines = ceil(CGFloat(size.height) / label.font.lineHeight)
return Int(lines)
}
return 0
}
Edit
If this method doesn't work for you because your label hasn't a fixed width, you can use boundingRectWithSize to get the size of the label and use that with the ceil method.
func countLabelLines(label:UILabel)->Int{
if let text = label.text{
// cast text to NSString so we can use sizeWithAttributes
var myText = text as NSString
//Set attributes
var attributes = [NSFontAttributeName : UIFont.systemFontOfSize(UIFont.systemFontSize())]
//Calculate the size of your UILabel by using the systemfont and the paragraph we created before. Edit the font and replace it with yours if you use another
var labelSize = myText.boundingRectWithSize(CGSizeMake(label.bounds.width, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributes, context: nil)
//Now we return the amount of lines using the ceil method
var lines = ceil(CGFloat(labelSize.height) / label.font.lineHeight)
return Int(lines)
}
return 0
}
Swift 3
A simple solution is counting the number of lines after assigning the string and compare to the max number of lines of the label.
import Foundation
import UIKit
extension UILabel {
func countLabelLines() -> Int {
// Call self.layoutIfNeeded() if your view is uses auto layout
let myText = self.text! as NSString
let attributes = [NSFontAttributeName : self.font]
let labelSize = myText.boundingRect(with: CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil)
return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight))
}
func isTruncated() -> Bool {
if (self.countLabelLines() > self.numberOfLines) {
return true
}
return false
}
}
This works for labels with fixed width and fixed number of lines or fixed height:
extension UILabel {
func willBeTruncated() -> Bool {
let label:UILabel = UILabel(frame: CGRectMake(0, 0, self.bounds.width, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = self.font
label.text = self.text
label.sizeToFit()
if label.frame.height > self.frame.height {
return true
}
return false
}
}
Related
I have a scenario where I'm needed to create an UIView completely programatically. This view is displayed as an overlay over a video feed and it contains 2 UILabels as subviews.
These labels can have varying widths and heights so I don't want to create a fixed frame for the UIView or the labels.
I've done this with programatic constrains without issue, but the problem is that the views are glitching when moving the phone and the framework that I'm using that does the video feed recommends not to use autolayout because of this exact problem.
My current code:
I create the view
func ar(_ arViewController: ARViewController, viewForAnnotation: ARAnnotation) -> ARAnnotationView {
let annotationView = AnnotationView() //*this is the view, inherits from UIView
annotationView.annotation = viewForAnnotation
annotationView.delegate = self
return annotationView
}
And the actual view code
class AnnotationView: ARAnnotationView {
var titleLabel: UILabel?
var distanceLabel: UILabel!
var delegate: AnnotationViewDelegate?
override var annotation: ARAnnotation? {
didSet {
loadUI()
}
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
setupUI()
}
private func setupUI() {
layer.cornerRadius = 5
layer.masksToBounds = true
backgroundColor = .transparentWhite
}
private func loadUI() {
titleLabel?.removeFromSuperview()
distanceLabel?.removeFromSuperview()
let label = UILabel()
label.font = UIFont(name: "AvenirNext-Medium", size: 16.0) ?? UIFont.systemFont(ofSize: 14)
label.numberOfLines = 2
label.textColor = UIColor.white
self.titleLabel = label
distanceLabel = UILabel()
distanceLabel.textColor = .cbPPGreen
distanceLabel.font = UIFont(name: "AvenirNext-Medium", size: 14.0) ?? UIFont.systemFont(ofSize: 12)
distanceLabel.textAlignment = .center
self.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
distanceLabel.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(label)
self.addSubview(distanceLabel)
if self.constraints.isEmpty {
NSLayoutConstraint.activate([
NSLayoutConstraint(item: label, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 5),
NSLayoutConstraint(item: label, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: -5),
NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: label, attribute: .bottom, relatedBy: .equal, toItem: distanceLabel, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: distanceLabel, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0),
NSLayoutConstraint(item: distanceLabel, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0),
NSLayoutConstraint(item: distanceLabel, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: distanceLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 15),
])
}
if let annotation = annotation as? BikeStationAR {
titleLabel?.text = annotation.address
distanceLabel?.text = String(format: "%.2f km", annotation.distanceFromUser / 1000)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
delegate?.didTouch(annotationView: self)
}
}
So my problem is now: how can I achieve the same behavior, without using autolayout?
Edit: here is a video of the behavior https://streamable.com/s/4zusq/dvbgnb
Edit 2: The solution is based on Mahgol Fa's answer and using a stack view or vertical positioning in order not to set the frame for the individual labels. So the final implementation is
private func loadUI() {
titleLabel?.removeFromSuperview()
distanceLabel?.removeFromSuperview()
let label = UILabel()
label.font = titleViewFont
label.numberOfLines = 0
label.textColor = UIColor.white
label.textAlignment = .center
self.titleLabel = label
distanceLabel = UILabel()
distanceLabel.textColor = .cbPPGreen
distanceLabel.font = subtitleViewFont
distanceLabel.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
distanceLabel.translatesAutoresizingMaskIntoConstraints = false
if let annotation = annotation as? BikeStationAR {
let title = annotation.address
let subtitle = String(format: "%.2f km", annotation.distanceFromUser / 1000)
let fontAttributeTitle = [NSAttributedString.Key.font: titleViewFont]
let titleSize = title.size(withAttributes: fontAttributeTitle)
let fontAttributeSubtitle = [NSAttributedString.Key.font: subtitleViewFont]
let subtitleSize = annotation.address.size(withAttributes: fontAttributeSubtitle)
titleLabel?.text = title
distanceLabel?.text = subtitle
let stackView = UIStackView(frame: CGRect(x: 0, y: 0, width: titleSize.width + 5, height: titleSize.height + subtitleSize.height + 5))
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.alignment = .fill
stackView.addArrangedSubview(titleLabel ?? UIView())
stackView.addArrangedSubview(distanceLabel)
frame = stackView.bounds
addSubview(stackView)
}
}
This way you can get the width of your lablels texts:
let fontAttributes1= [NSAttributedStringKey.font: your declared font in your code]
let size1 = (“your string” as String).size(withAttributes: fontAttributes1)
let fontAttributes2= [NSAttributedStringKey.font: your declared font in your code]
let size2 = (“your string” as String).size(withAttributes: fontAttributes2)
Then :
YourView.frame = CGRect( width: size1.width + size2.width + some spacing , height : ....)
I'm working with a UIScrollView where I want to show images, but the problem is that I need those images to be shown horizontally and now they are only shown vertically, how can I change the direction of my UIScrollView, from vertical to horizontal
This is my class where you implemented the UIScrollView:
//
// fastoClass.swift
// AutoLayout(
// Created by Barbatos on 5/14/18.
// Copyright © 2018 Seccion 15. All rights reserved.
//
import UIKit
class fastoClass: UIViewController {
#IBOutlet weak var scrollHorizont: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
var constraints = [NSLayoutConstraint]()
var i = 0
var previousLeft: UIView? = nil
var previousRight: UIView? = nil
let scrollWidth: CGFloat = self.scrollHorizont.frame.size.width / 2.0
let imageColors = [UIColor.green, UIColor.lightGray, UIColor.blue, UIColor.red]
for color in imageColors{
let newImage = UIImageView()
newImage.backgroundColor = color
newImage.translatesAutoresizingMaskIntoConstraints = false
var toView : UIView? = nil
var toAttribute : NSLayoutAttribute?
let isLeft = (i % 2) == 0
if isLeft {
toView = self.scrollHorizont
toAttribute = NSLayoutAttribute.leading
} else {
toView = previousLeft
toAttribute = NSLayoutAttribute.trailing
}
var topView : UIView? = nil
var topAttribute : NSLayoutAttribute?
if i < 2 {
topView = self.scrollHorizont
topAttribute = NSLayoutAttribute.top
} else {
if isLeft {
topView = previousLeft
} else {
topView = previousRight
}
topAttribute = NSLayoutAttribute.bottom
}
let top = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.top,
relatedBy: NSLayoutRelation.equal,
toItem: topView,
attribute: topAttribute!,
multiplier: 1.0,
constant: 0)
let leading = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.leading,
relatedBy: NSLayoutRelation.equal,
toItem: toView,
attribute: toAttribute!,
multiplier: 1.0,
constant: 0)
let width = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.width,
relatedBy: NSLayoutRelation.equal,
toItem: self.scrollHorizont,
attribute: NSLayoutAttribute.width,
multiplier: 0.5,
constant: 0)
let height = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.height,
relatedBy: NSLayoutRelation.equal,
toItem: nil,
attribute: NSLayoutAttribute.notAnAttribute,
multiplier: 1.0,
constant: scrollWidth)
constraints.append(top)
constraints.append(leading)
constraints.append(width)
constraints.append(height)
self.scrollHorizont.addSubview(newImage)
i += 1
if isLeft {
previousLeft = newImage
} else {
previousRight = newImage
}
}
self.scrollHorizont.addConstraints(constraints)
self.scrollHorizont.layoutSubviews()
let contentHeight : CGFloat = scrollWidth * (CGFloat(i) / 2.0)
self.scrollHorizont.contentSize = CGSize(width: self.scrollHorizont.frame.size.width, height: contentHeight)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You can try this
override func viewDidAppear(_ animated: Bool) {
var constraints = [NSLayoutConstraint]()
var i = 0
var previousLeft: UIView? = nil
let imageColors = [UIColor.green, UIColor.lightGray, UIColor.blue, UIColor.red]
for color in imageColors{
let newImage = UIImageView()
newImage.backgroundColor = color
newImage.translatesAutoresizingMaskIntoConstraints = false
if previousLeft == nil {
previousLeft = scrollHorizont
}
var con:NSLayoutAttribute? = nil
if previousLeft == self.scrollHorizont {
con = NSLayoutAttribute.leading
}
else {
con = NSLayoutAttribute.trailing
}
self.scrollHorizont.addSubview(newImage)
let top = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.top,
relatedBy: NSLayoutRelation.equal,
toItem: previousLeft,
attribute: NSLayoutAttribute.top,
multiplier: 1.0,
constant: 0)
let leading = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.leading,
relatedBy: NSLayoutRelation.equal,
toItem: previousLeft,
attribute: con!,
multiplier: 1.0,
constant: 0)
let width = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.width,
relatedBy: NSLayoutRelation.equal,
toItem: self.scrollHorizont,
attribute: NSLayoutAttribute.width,
multiplier: 1,
constant: 0)
let height = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.height,
relatedBy: NSLayoutRelation.equal,
toItem: self.scrollHorizont,
attribute: NSLayoutAttribute.height,
multiplier: 1.0,
constant: 0)
if i == imageColors.count - 1 {
let tra = NSLayoutConstraint(item: newImage,
attribute: NSLayoutAttribute.trailing,
relatedBy: NSLayoutRelation.equal,
toItem: self.scrollHorizont,
attribute: NSLayoutAttribute.trailing,
multiplier: 1.0,
constant: 0)
constraints.append(tra)
}
constraints.append(top)
constraints.append(leading)
constraints.append(width)
constraints.append(height)
previousLeft = newImage
i += 1
}
self.scrollHorizont.addConstraints(constraints)
}
I'm creating a several labels, based on the count of my array. And that works fine. But after some user interaction happens, I'd like to change the label color.
Here is my code:
-The array looks something like this:
var vids = [5: ["urltovideo1", "locationOne"], 7: ["urltovideo2", "locationTwo"]]
for label in vids[x][1] {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = UIColor.gray
label.text = vids[index[j] as! Int]![2]
let z = CGFloat(j)
self.view.addSubview(label)
let horConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 0.3+z, constant: 0.0)
let verConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 0.75, constant: 0.0)
view.addConstraints([horConstraint, verConstraint])
}
-After the user interacts with the app, I try doing this:
for label in vids[x][1] {
let label = UILabel()
label.backgroundColor = UIColor.green
}
...but nothing happens.
If you are doing namely this:
for label in vids[x][1] {
let label = UILabel()
label.backgroundColor = UIColor.green
}
Your labels will not be changed. The problem is that at line let label = UILabel() you just create a new instance of UILabel. This label is not the label you see on the iPhone screen.
One of the possible solutions.
Create somewhere in your class a storage of UILabels that you create in the first loop.
var vids = [5: ["urltovideo1", "locationOne"], 7: ["urltovideo2", "locationTwo"]]
var labels: [String: UILabel] = [:]
for labelString in vids[x][1] {
let label = UILabel()
labels[labelString] = label
label.translatesAutoresizingMaskIntoConstraints = false
label.backgroundColor = UIColor.gray
label.text = vids[index[j] as! Int]![2]
let z = CGFloat(j)
self.view.addSubview(label)
let horConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 0.3+z, constant: 0.0)
let verConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 0.75, constant: 0.0)
view.addConstraints([horConstraint, verConstraint])
}
and use it later:
for labelString in vids[x][1] {
let label = labels[labelString] // < Here you retrieves a saved label
label.backgroundColor = UIColor.green
}
I would like to achieve the same result as this :
I already saw this : Draw line in UILabel before and after text , but I would like to know if there's a way to do this with only one UILabel ?
This is custom view as you requested
import UIKit
class CustomizedUILabel: UIView
{
let label = UILabel()
var lineInsideOffset: CGFloat = 20
var lineOutsideOffset: CGFloat = 4
var lineHeight: CGFloat = 1
var lineColor = UIColor.grayColor()
//MARK: - init
override init(frame: CGRect)
{
super.init(frame: frame)
initLabel()
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
initLabel()
}
convenience init() {self.init(frame: CGRect.zero)}
func initLabel()
{
label.textAlignment = .Center
label.translatesAutoresizingMaskIntoConstraints = false
let top = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: label, attribute: .Top, multiplier: 1, constant: 0)
let bot = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: label, attribute: .Bottom, multiplier: 1, constant: 0)
let lead = NSLayoutConstraint(item: self, attribute: .Leading, relatedBy: .LessThanOrEqual, toItem: label, attribute: .Leading, multiplier: 1, constant: 0)
let trail = NSLayoutConstraint(item: self, attribute: .Trailing, relatedBy: .GreaterThanOrEqual, toItem: label, attribute: .Trailing, multiplier: 1, constant: 0)
let centerX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: label, attribute: .CenterX, multiplier: 1, constant: 0)
addSubview(label)
addConstraints([top, bot, lead, trail, centerX])
//... if the opaque property of your view is set to YES, your drawRect: method must totally fill the specified rectangle with opaque content.
//http://stackoverflow.com/questions/11318987/black-background-when-overriding-drawrect-in-uiscrollview
opaque = false
}
//MARK: - drawing
override func drawRect(rect: CGRect)
{
let lineWidth = label.frame.minX - rect.minX - lineInsideOffset - lineOutsideOffset
if lineWidth <= 0 {return}
let lineLeft = UIBezierPath(rect: CGRectMake(rect.minX + lineOutsideOffset, rect.midY, lineWidth, 1))
let lineRight = UIBezierPath(rect: CGRectMake(label.frame.maxX + lineInsideOffset, rect.midY, lineWidth, 1))
lineLeft.lineWidth = lineHeight
lineColor.set()
lineLeft.stroke()
lineRight.lineWidth = lineHeight
lineColor.set()
lineRight.stroke()
}
}
Usage in code: in usual case you should provide top, leading and trailing/width constraints and let CustomizedUILabel to determine height by its internal UILabel. Lets show our label in debug mode in some view controller's viewDidLoad method:
override func viewDidLoad()
{
super.viewDidLoad()
let customizedLabel = CustomizedUILabel()
customizedLabel.label.text = "RATE YOUR RIDE"
customizedLabel.label.textColor = UIColor.grayColor()
customizedLabel.label.font = customizedLabel.label.font.fontWithSize(25)
customizedLabel.backgroundColor = UIColor.redColor()
view.addSubview(customizedLabel)
customizedLabel.translatesAutoresizingMaskIntoConstraints = false
let top = NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: customizedLabel, attribute: .Top, multiplier: 1, constant: -100)
let trail = NSLayoutConstraint(item: view, attribute: .Trailing, relatedBy: .Equal, toItem: customizedLabel, attribute: .Trailing, multiplier: 1, constant: 0)
let lead = NSLayoutConstraint(item: view, attribute: .Leading, relatedBy: .Equal, toItem: customizedLabel, attribute: .Leading, multiplier: 1, constant: 0)
view.addConstraints([top, trail, lead])
}
Usage in xib/storyboard: as soon as you implemented init with coder initializer you can use this view in xib/storyboard. You need add UIView element to your superview, assign Class for this element to CustomizedUILabel, perform constraints and make outlet. Then you can use it with pretty same way:
#IBOutlet weak var customizedLabel: CustomizedUILabel!
override func viewDidLoad()
{
super.viewDidLoad()
customizedLabel.label.text = "RATE YOUR RIDE"
customizedLabel.label.textColor = UIColor.grayColor()
customizedLabel.label.font = customizedLabel.label.font.fontWithSize(25)
customizedLabel.backgroundColor = UIColor.redColor()
}
UILabel * label = [UILabel new];
label.frame = CGRectMake(0,0,0,20);
label.text = #"Rate Your Ride";
[self.view addSubview:label];
[label sizeToFit];
float w = self.view.frame.size.width;
float lw = label.frame.size.width;
float offset = (w-lw)/2;
float padding = 20.0f;
//center the label
[label setFrame:CGRectMake(offset, 0, lw, 20)];
//make the borders
UIImageView * left = [UIImageView new];
left.frame = CGRectMake(0, 9, offset-padding, 2);
left.backgroundColor = [UIColor blackColor];
[self.view addSubview:left];
UIImageView * right = [UIImageView new];
right.frame = CGRectMake(w-offset+padding, 9, offset-padding, 2);
right.backgroundColor = [UIColor blackColor];
[self.view right];
OR
make the label background the same colour as its parent and put a single line behind it.
I am currently working on a custom keyboard
and I encountered a problem when I try to combine the textDocumentProxy in a new window
So have add emoji keyboard button
and which I pass page with the addition of two buttons of emoji Now my problem is how I can incorporate textDocumentProxy another window or link between them waned even can type emoji
I try to type anything not only emoji
Full source code is here
https://github.com/archagon/tasty-imitation-keyboard
import UIKit
class DefaultSettings1: ExtraView, UITableViewDelegate {
#IBOutlet var tableView1: UITableView?
#IBOutlet var effectsView: UIVisualEffectView?
#IBOutlet var backButton1: UIButton?
#IBOutlet var settingsLabel: UILabel?
#IBOutlet var pixelLine: UIView?
#IBOutlet var keyPressed: UIButton?
override var darkMode: Bool {
didSet {
self.updateAppearance(darkMode)
}
}
let cellBackgroundColorDark = UIColor.whiteColor().colorWithAlphaComponent(CGFloat(0.25))
let cellBackgroundColorLight = UIColor.whiteColor().colorWithAlphaComponent(CGFloat(1))
let cellLabelColorDark = UIColor.whiteColor()
let cellLabelColorLight = UIColor.blackColor()
let cellLongLabelColorDark = UIColor.lightGrayColor()
let cellLongLabelColorLight = UIColor.grayColor()
// TODO: these probably don't belong here, and also need to be localized
required init(globalColors: GlobalColors.Type?, darkMode: Bool, solidColorMode: Bool) {
super.init(globalColors: globalColors, darkMode: darkMode, solidColorMode: solidColorMode)
self.loadNib()
}
required init(coder aDecoder: NSCoder) {
fatalError("loading from nib not supported")
}
func loadNib() {
let assets = NSBundle(forClass: self.dynamicType).loadNibNamed("DefaultSettings1", owner: self, options: nil)
if assets.count > 0 {
if var rootView = assets.first as? UIView {
rootView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addSubview(rootView)
let left = NSLayoutConstraint(item: rootView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: rootView, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
let top = NSLayoutConstraint(item: rootView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
let bottom = NSLayoutConstraint(item: rootView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
self.addConstraint(left)
self.addConstraint(right)
self.addConstraint(top)
self.addConstraint(bottom)
}
}
self.tableView1?.registerClass(DefaultSettings1TableViewCell.self, forCellReuseIdentifier: "cell")
self.tableView1?.estimatedRowHeight = 44;
self.tableView1?.rowHeight = UITableViewAutomaticDimension;
// XXX: this is here b/c a totally transparent background does not support scrolling in blank areas
self.tableView1?.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.01)
self.updateAppearance(self.darkMode)
}
func tableView1(tableView1: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if var cell = tableView1.dequeueReusableCellWithIdentifier("cell") as? DefaultSettings1TableViewCell {
if cell.sw.allTargets().count == 0 {
cell.sw.addTarget(self, action: Selector("toggleSetting1:"), forControlEvents: UIControlEvents.ValueChanged)
}
cell.backgroundColor = (self.darkMode ? cellBackgroundColorDark : cellBackgroundColorLight)
cell.label.textColor = (self.darkMode ? cellLabelColorDark : cellLabelColorLight)
cell.longLabel.textColor = (self.darkMode ? cellLongLabelColorDark : cellLongLabelColorLight)
cell.changeConstraints()
return cell
}
else {
assert(false, "this is a bad thing that just happened")
return UITableViewCell()
}
}
func updateAppearance(dark: Bool) {
if dark {
self.effectsView?.effect
let blueColor = UIColor(red: 135/CGFloat(255), green: 206/CGFloat(255), blue: 250/CGFloat(255), alpha: 1)
self.pixelLine?.backgroundColor = blueColor.colorWithAlphaComponent(CGFloat(0.5))
self.backButton1?.setTitleColor(blueColor, forState: UIControlState.Normal)
self.settingsLabel?.textColor = UIColor.whiteColor()
if let visibleCells = self.tableView1?.visibleCells() {
for cell in visibleCells {
if var cell = cell as? UITableViewCell {
cell.backgroundColor = cellBackgroundColorDark
var label = cell.viewWithTag(2) as? UILabel
label?.textColor = cellLabelColorDark
var longLabel = cell.viewWithTag(3) as? UITextView
longLabel?.textColor = cellLongLabelColorDark
}
}
}
}
else {
let blueColor = UIColor(red: 0/CGFloat(255), green: 122/CGFloat(255), blue: 255/CGFloat(255), alpha: 1)
self.pixelLine?.backgroundColor = blueColor.colorWithAlphaComponent(CGFloat(0.5))
self.backButton1?.setTitleColor(blueColor, forState: UIControlState.Normal)
self.settingsLabel?.textColor = UIColor.grayColor()
if let visibleCells = self.tableView1?.visibleCells() {
for cell in visibleCells {
if var cell = cell as? UITableViewCell {
cell.backgroundColor = cellBackgroundColorLight
var label = cell.viewWithTag(2) as? UILabel
label?.textColor = cellLabelColorLight
var longLabel = cell.viewWithTag(3) as? UITextView
longLabel?.textColor = cellLongLabelColorLight
}
}
}
}
}
}
class DefaultSettings1TableViewCell: UITableViewCell {
var sw: UISwitch
var label: UILabel
var longLabel: UITextView
var constraintsSetForLongLabel: Bool
var cellConstraints: [NSLayoutConstraint]
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
self.sw = UISwitch()
self.label = UILabel()
self.longLabel = UITextView()
self.cellConstraints = []
self.constraintsSetForLongLabel = false
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.sw.setTranslatesAutoresizingMaskIntoConstraints(false)
self.label.setTranslatesAutoresizingMaskIntoConstraints(false)
self.longLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
self.longLabel.text = nil
self.longLabel.scrollEnabled = false
self.longLabel.selectable = false
self.longLabel.backgroundColor = UIColor.clearColor()
self.sw.tag = 1
self.label.tag = 2
self.longLabel.tag = 3
self.addSubview(self.sw)
self.addSubview(self.label)
self.addSubview(self.longLabel)
self.addConstraints()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addConstraints() {
let margin: CGFloat = 8
let sideMargin = margin * 2
let hasLongText = self.longLabel.text != nil && !self.longLabel.text.isEmpty
if hasLongText {
let switchSide = NSLayoutConstraint(item: sw, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: -sideMargin)
let switchTop = NSLayoutConstraint(item: sw, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: margin)
let labelSide = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: sideMargin)
let labelCenter = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: sw, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
self.addConstraint(switchSide)
self.addConstraint(switchTop)
self.addConstraint(labelSide)
self.addConstraint(labelCenter)
let left = NSLayoutConstraint(item: longLabel, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: sideMargin)
let right = NSLayoutConstraint(item: longLabel, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: -sideMargin)
let top = NSLayoutConstraint(item: longLabel, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: sw, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: margin)
let bottom = NSLayoutConstraint(item: longLabel, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: -margin)
self.addConstraint(left)
self.addConstraint(right)
self.addConstraint(top)
self.addConstraint(bottom)
self.cellConstraints += [switchSide, switchTop, labelSide, labelCenter, left, right, top, bottom]
self.constraintsSetForLongLabel = true
}
else {
let switchSide = NSLayoutConstraint(item: sw, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: -sideMargin)
let switchTop = NSLayoutConstraint(item: sw, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: margin)
let switchBottom = NSLayoutConstraint(item: sw, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: -margin)
let labelSide = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: sideMargin)
let labelCenter = NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: sw, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
self.addConstraint(switchSide)
self.addConstraint(switchTop)
self.addConstraint(switchBottom)
self.addConstraint(labelSide)
self.addConstraint(labelCenter)
self.cellConstraints += [switchSide, switchTop, switchBottom, labelSide, labelCenter]
self.constraintsSetForLongLabel = false
}
}
// XXX: not in updateConstraints because it doesn't play nice with UITableViewAutomaticDimension for some reason
func changeConstraints() {
let hasLongText = self.longLabel.text != nil && !self.longLabel.text.isEmpty
if hasLongText != self.constraintsSetForLongLabel {
self.removeConstraints(self.cellConstraints)
self.cellConstraints.removeAll()
self.addConstraints()
}
}
}
You need to change many things into your project as per your requirement like you can use that setting view by hiding that tableView and add one UIView on it after that you can add emojis into that view and when user click on setting button from keyboard you can hide your emojis view and show tableview but when user want to type smiles that you don't need to hide anything just show your emojis view.
HERE is your updated project.