get rid of the space under the text of UITextView - swift

I'm currently working on making a custom UITextView class.
As you can see in the image, there is bigger space between the text in line 1 and line 2.
The blue cursor represents the height of the text, however, like line 2's text, the gray background has a height around 2 times bigger than the text.
After some research, I thought change the NSMutableParagraphStyle's lineSpacing will fix the problem I have (but it didn't). Is changing the lineSpacing or MutableParagraphStyle won't change the line-height?
import UIKit
class CustomTextView: UITextView {
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init() {
super.init(frame: .zero, textContainer: nil)
configure()
}
private func configure() {
translatesAutoresizingMaskIntoConstraints = false
font = UIFont.myCustomFont()
let textStyle = NSMutableParagraphStyle()
textStyle.lineSpacing = 1.0
textStyle.paragraphSpacing = 1.0
let attributes: Dictionary = [NSAttributedString.Key.paragraphStyle: textStyle]
attributedText = NSAttributedString(string: self.text, attributes: attributes)
}
override func caretRect(for position: UITextPosition) -> CGRect {
var superRect = super.caretRect(for: position)
guard let font = self.font else { return superRect }
superRect.size.height = font.pointSize
return superRect
}
}
Added this part later...
So, when I delete the line for setting the font, I was able to get rid of the bigger space (but lost the custom font).
So I think the custom font has something like a bottom padding? I guess. I created a font like this, but do you see any problem or any clue why I get the bottom space, like the gray area in the image?
extension UIFont {
static func myCustomFont() -> UIFont {
return UIFont(name: "Custom Font", size: 18)!
}
}

Related

Label Colours on an #IBDesignable View appearing different of different devices

I have an #IBDesignable custom view. It contain an UIView with two subclassed UILabels. The custom subclass of UILabel is setting it's font.
What I'm trying to achieve is by changing by making the background colour of the view an inspectable property that the text colour change appropriately to be legible.
My code is below. Custom.Colour.<name> is just an enum of defined colours.
#IBDesignable
class CustomMiniView: UIView, NibLoadable {
public var view:UIView!
#IBOutlet weak var colourView: UIView!
#IBOutlet weak var headingLabel: CustomUILabel!
#IBOutlet weak var amountLabel: CustomUILabel!
#IBInspectable var blockColor:UIColor! {
didSet {
self.colourView.backgroundColor = blockColor
switch blockColor {
case Custom.Colour.darkBlue:
headingLabel.textColor = .white
amountLabel.textColor = .white
case Custom.Colour.blue:
headingLabel.textColor = .white
amountLabel.textColor = .white
case Custom.Colour.lightBlue:
headingLabel.textColor = Custom.Colour.grey
amountLabel.textColor = Custom.Colour.blue
case Custom.Colour.green:
headingLabel.textColor = .white
amountLabel.textColor = .white
case Custom.Colour.lightGreen:
headingLabel.textColor = Custom.Colour.grey
amountLabel.textColor = Custom.Colour.blue
case Custom.Colour.yellow:
headingLabel.textColor = Custom.Colour.grey
amountLabel.textColor = Custom.Colour.grey
default : printError("We have not handled text colours for a background of this colour. = \(blockColor.hexString)")
}
}
}
public override init(frame: CGRect) {
super.init(frame: frame)
self.setupFromNib()
self.commonInit()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupFromNib()
self.commonInit()
}
func commonInit() {
self.backgroundColor = .clear
}
}
This was working for me fine, however I was then getting report that the text was showing up as white everywhere and got sent a screen shot which confused me. When I ran this in a simulator and a different device I was able to see this not working. Here are two screen shots of what is happening on my iPad and what I expect to happen and a screen shot of what is happening on some other devices and the simulator.
This is what is happening on my device and the expected result.
This is whats happening on other devices and the incorrect result.
Is there a reason this would appeared different of different devices? I'm at a loss to the cause or how to fix this.
Thanks to comments above I've found a fix.
Rather than doing a switch on the colour I've done a switch on the .hexString of the colour which has worked.
switch blockColor.hexString {
case Custom.Colour.darkBlue.hexString :
for the record hexString is an extension to UIColor
var hexString: String {
let colorRef = cgColor.components
let r = colorRef?[0] ?? 0
let g = colorRef?[1] ?? 0
let b = ((colorRef?.count ?? 0) > 2 ? colorRef?[2] : g) ?? 0
let a = cgColor.alpha
var color = String(
format: "#%02lX%02lX%02lX",
lroundf(Float(r * 255)),
lroundf(Float(g * 255)),
lroundf(Float(b * 255))
)
if a < 1 {
color += String(format: "%02lX", lroundf(Float(a)))
}
return color
}
I'm still not sure why switching on hexString worked and the UIColor in the enum did not work consistently but thanks to comments about that helped me find a solution to fix it myself. Question for another time is why switching on UIColor would be unreliable but now back to work.

Nested UITableView dynamic height

I need to have a nested UITableView in a tableView cell (actually, two tables in one cell) to show different lists with dynamic content (so, I need dynamic heights). My nested tables will not have scrolling—I need them just to order elements of different kinds, like texts, pictures, fields etc. To be more clear—the first level is the level of operations and every operation can have a variable amount of instructions and actions. Instructions and actions should be placed side by side and the operation cell should have the size of the tallest table.
There are no problems in nesting tables, but I faced a problem with the auto layout. I’ve tried everything that I could find, but with no success.
I tried height constraints for nested table views, which I update on the operation cell creation from tableview.contentsize.hight, but it seems that contentsize returns height based on the estimated size of every row, but not the actual size.
I tried to rewrite intrinsic content size of nested tables:
UITableView {
override var contentSize:CGSize {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
}
}
Nothing works properly. Any ideas how it could be solved?
Thank you in advance.
Set Inner tableview my custom class AGTableView and height Constraint both are required,
this class set contantSize same table view height Constraint.
Check out Github AutoHeightIncrementTableViewDemo
class AGTableView: UITableView {
fileprivate var heightConstraint: NSLayoutConstraint!
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
self.associateConstraints()
defaultInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.associateConstraints()
defaultInit()
}
func defaultInit(){
self.keyboardDismissMode = .onDrag
self.showsVerticalScrollIndicator = false
self.showsHorizontalScrollIndicator = false
self.tableFooterView = UIView(frame: .zero)
self.tableHeaderView = UIView(frame: .zero)
self.sectionFooterHeight = 0
self.sectionHeaderHeight = 0
}
override open func layoutSubviews() {
super.layoutSubviews()
if self.heightConstraint != nil {
self.heightConstraint.constant = self.contentSize.height
}
else{
print("Set a heightConstraint to set cocontentSize with same")
}
}
func associateConstraints() {
// iterate through all text view's constraints and identify
// height
for constraint: NSLayoutConstraint in constraints {
if constraint.firstAttribute == .height {
if constraint.relation == .equal {
heightConstraint = constraint
}
}
}
}
}
NOTE: Also set a estimatedRowHeight
self.rowHeight = UITableViewAutomaticDimension
self.estimatedRowHeight = height

How to change font size of NSTableHeaderCell

I am trying to change the font size of my NSTableView within my code to allow the user to change it to their liking.
I was successful by changing the font size of each NSTableCellView but failed to do so by the header cells.
I was trying to do it like this
let headerCell = NSTableHeaderCell()
let font = NSFont(name: "Arial", size: 22.0)
headerCell.stringValue = "firstname"
headerCell.font = font
customerTable.tableColumns[0].headerCell = headerCell
The stringValue of the header cell will be set accordingly but the size does not change. How can I change the font size of my headers?
Thanks
Oliver
So, finally I was only able to solve this with subclassing NSTableHeaderCell. It was somehow strange as Swift and Cocoa always tend to favor composition over inheritance but anyway.
Swift 3.1
final class CustomTableHeaderCell : NSTableHeaderCell {
override init(textCell: String) {
super.init(textCell: textCell)
self.font = NSFont.boldSystemFont(ofSize: 18) // Or set NSFont to your choice
self.backgroundColor = NSColor.white
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
// skip super.drawWithFrame(), since that is what draws borders
self.drawInterior(withFrame: cellFrame, in: controlView)
}
override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
let titleRect = self.titleRect(forBounds: cellFrame)
self.attributedStringValue.draw(in: titleRect)
}
}
Changing attributedStringValue will do the trick
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableColumns.forEach { (column) in
column.headerCell.attributedStringValue = NSAttributedString(string: column.title, attributes: [NSFontAttributeName: NSFont.boldSystemFont(ofSize: 18)])
// Optional: you can change title color also jsut by adding NSForegroundColorAttributeName
}
}
https://i.stack.imgur.com/IXJyu.png
You can create a NSTableHeaderCell subclass and implement the property you want to change.
In Objective-C (I'm not good at Swift):
#implementation CustomTableHeaderCell
-(NSFont *)font {
return [NSFont fontWithName:#"Arial" size:22];
}
// you can alse custom textColor
-(NSColor *)textColor {
return [NSColor redColor];
}
#end
Assign CustomTableHeaderCell:
CustomTableHeaderCell *headerCell = [[CustomTableHeaderCell alloc] init];
headerCell.stringValue = #"Header title";
self.tableView.tableColumns[0].headerCell = headerCell;
In Cocoa, there are many things you can't change its style by cell.font = ..., you need to create a subcalss.

How do I set UISlider to have only one track image rather than using a minimum track image and a maximum track image in Swift?

Hello I was wondering how to just have one track image for my customized slider. I am having an issue where if I set the minimum track image and the maximum track image using the same image, my slider has a gap in the thumb image such as in this picture. .
This is my custom class UISlider code.
import UIKit
class NightVisionSlider: UISlider {
required init?(coder: NSCoder) {
super.init(coder:coder)
self.setThumbImage(UIImage(named:"Night Vision Slider Knob3.png")!, for:.normal)
let trackingImage = UIImage(named:"Night Vision Bar 2.png")!
self.setMinimumTrackImage(trackingImage, for:.normal)
self.setMaximumTrackImage(trackingImage, for:.normal)
}
}
How can I just have one complete tracking image, so my slider doesn't have this flaw?
class CustomSlider: UISlider
{
override func awakeFromNib()
{
super.awakeFromNib()
self.setThumbImage(UIImage(named:"Night Vision Slider Knob3.png")!, for:.normal)
let trackingImage = UIImage(named:"Night Vision Bar 2.png")!
self.setMinimumTrackImage(trackingImage, for:.normal)
self.setMaximumTrackImage(trackingImage, for:.normal)
}
override func layoutSubviews()
{
super.layoutSubviews()
super.layer.cornerRadius = self.frame.height/2 //Do something additional if you want to do!.
}
override func trackRect(forBounds bounds: CGRect) -> CGRect
{
var newBounds = super.trackRect(forBounds: bounds)
newBounds.size.height = 10 //Size of your track
return newBounds
}
}

Using a CALayer in an NSStatusBarButton

I'm interested in drawing custom content in a NSStatusBarButton similar to the built-in battery menu bar app:
I'd like to use a CALayer due to the flexibility of drawing custom content. I've managed to add a layer-backed NSView to the button using this code:
// StatusView
class StatusView: NSView {
required init?(coder: NSCoder) {
super.init(coder: coder)
self.wantsLayer = true
}
override var wantsUpdateLayer: Bool {
return true
}
override func updateLayer() {
if let layer = self.layer {
layer.backgroundColor = NSColor.clear.cgColor
// Code adding text layer...
}
}
}
// MenuController
class StatusMenuController: NSObject {
override func awakeFromNib() {
if let button = statusItem.button {
layerView.frame = NSRect(x: 0.0, y: 0.0, width: len / 2, height: button.bounds.height)
button.addSubview(layerView)
}
}
}
Basically I'm adding a CALayer to the button of the NSStatusBarButton, which looks fine normally, but seems to have an opaque background when you click the menu item:
I've set the background color of the CALayer to transparent and the isOpaque property of the layer's view is false. Is there a way to get the view to actually blend with the background, similar to the battery menu bar app?
Thanks!