tvOS: UILabel not resizing when focusing on custom UITableViewCell - swift

I created a view programmatically and added a tableview to it.
For that tableview, I created a cell programmatically, but now when I scroll through the cells on the Apple tv, the label does not have the magnifying standard effect and half of the text gets hidden (which half depends if you're going up or down) (see picture).
Does anyone know a solution to this?
Here is also the init for my uitableviewcell:
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
optionLabel = UILabel(frame: CGRectMake(20,20,400,50))
self.focusStyle = .Default
addSubview(optionLabel)
}

I just found the problem, when adding to a programmatically created cell, you need to use self.contentView.addSubview instead of just addSubview.
This did put my label back on the top.

Related

UIStackView, Autolayout, Table Cells

I'm creating a UIStackView with an image and a label in a custom UIControl that will be in a custom UITableViewCell, except that my UIStackView has a height & width of 0 and XCode is complaining about breaking constraints. Only if I explicitly set a height and width does it show properly, which I don't want because the label text varies from cell to cell. (This is all happening programmatically.)
The Setup
In my UITableViewCell, I've got the following:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(control)
NSLayoutConstraint.activate([
control.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
control.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
control.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
control.topAnchor.constraint(equalTo: contentView.topAnchor),
])
}
// empty coder init as well
private let control: MyControl = {
let control: MyControl = MyControl()
control.translatesAutoresizingMaskIntoConstraints = false
return control
}()
In MyControl, I just have the UIStackView, a UIImageView, and a UILabel. To not bore you with code...only the UIStackView (horizontal axis) is using constraints, pinning it to the four sides. The UIImageView (initiated with an image) is one arranged subview, the UILabel is the other (initiated with default text).
If you want to see the code:
class MyControl: UIControl {
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(stackView)
stackView.addArrangedSubview(icon)
stackView.addArrangedSubview(contentLabel)
NSLayoutConstraint.activate([
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
])
}
// empty coder init as well
private let contentLabel: UILabel = {
let label: UILabel = UILabel()
label.text = "Initial text"
return label
}()
private let icon: UIImageView = {
let iv: UIImageView = UIImageView(image: UIImage(named: "placeholder_image")!)
iv.contentMode = .scaleAspectFit
return iv
}()
private let stackView: UIStackView = {
let stackView: UIStackView = UIStackView()
stackView.axis = .horizontal
stackView.translatesAutoresizingMaskIntoConstraints = false
return control
}()
}
What I'm Expecting
I'm expecting the UIControl to be the height of the image (because it's taller than the label text), and the width of the image + the label text. (And then display full table cell width because of that constraint pinning). And because these are set on initialization of these components, I'd expect them to have an intrinsic height and width to pass to the UIStackView.
What I'm Getting
A height and width of zero, and XCode complaints of broken constraints. If I remove all constraints, I get no complaints but nothing appears (as if the height & width are zero but XCode doesn't care because I didn't set any constraints).
What I've Tried
Literally every combination of layout constraints, including none on everything and as many as I can on everything. What I'd like is for the image + label text to set the height and width of the UIStackView which would then set the height and width of the UIControl, which would then set the height in the UITableViewCell (I know I have width 100% - that will change later).
Other Considerations
There's nothing else special about my UITableViewCell that would cause any issue here except that in my actual code, I have a multi-line label above MyControl which should (and does) cause my UITableViewCell to expand in height.
The problem with your question is that so much of the code you've shown is bogus that it's hard to guess what you might actually be doing. You claim that in your table view cell (I presume it's a table view cell subclass) you are saying
override init(frame: CGRect) {
super.init(frame: frame)
But that would never compile, as init(frame:) is not the designated initializer for a UITableViewCell. You have code like this:
private let contentLabel: UILabel = {
let label: UILabel = UILabel()
label.text = "Initial text"
return label
}
But that would never compile, as a function is not a label.
If we make allowances for all of that and fix your code, it's difficult to see what you would be doing wrong. I corrected your code so that it would compile, and I got this in my table view:
That might not be exactly what you were after, but the image view is certainly sizing the cells to its own height.
What you are doing is not at all how one makes and configures a table view cell (you should be doing the work in cellForRowAt, not hard coding the cell's image view and label contents in the cell's initializer), but given what you've shown, the image view does size the stack view which does size the cell (contrary to my own initial expectations).
Another issue is that you can't put an image view and a label into an autolayout situation without resolving the ambiguity as to which should predominate. I added this line to do that:
iv.setContentHuggingPriority(.defaultLow+1, for: .horizontal)

Obtaining UILabel width when not occupying full screen width?

I would like to obtain the width of a UILabel added as a subView inside a custom TableView Cell. The TableView Class I am using is listed below:
import UIKit
class customTableViewCell: UITableViewCell {
let customLabel: UILabel = {
let label = UILabel()
label.translateAutoConstraints = false
label.textAlignment = .left
return label
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(customLabel)
customLabel.topAnchor.constraint(equal: contentView.topAnchor).isActive = true
customLabel.leftAnchor.constraint(equal: contentView.leftAnchor, constant: 10).isActive = true
customLabel.rightAnchor.constraint(equal: contentView.rightAnchor, constant: (contentView.frame.size.width/2)-10-customLabel.frame.size.width).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError(“init(coder:) has not been implemented”)
}
}
However, from the above code when I assigned the rightAnchor constraint for the customLabel UILabel, Xcode did not return the correct width of the UILabel I was looking for.
I understand that I only specified the top and left constraints for the UILabel. I also know that UILabel by default has intrinsic layout on, that it can decide on the required height based on the content of the UILabel. However, I am wondering if I did not set the numberOfLines for the customUILabel defined in the above code as 0 (i.e., I only want my text inside the UILabel to occupy one line only). Can I obtain the width of the customUILabel before the text got truncated.
Let me explain further, if my customLabel has a lot of text, it will occupy the full width of the screen then gets truncated. However, if it does not contain a lot of text, then it’s width will be less than the width of the screen. And this is exactly what I am interested in obtaining, the width of the UILabel used to display the small text inside it?
Regards,
Shadi.
You need
self.contentView.rightAnchor.constraintGreaterThanOrEqualToAnchor(customLabel.rightAnchor, constant: 8.0).active = true
Then print the width inside
override func layoutSubviews() {
super.layoutSubviews()
print(customLabel.frame.width)
}
Don't use frames in constraints calculations
(contentView.frame.size.width/2)-10-customLabel.frame.size.width
Inside cell init they not yet calculated

YPDrawSignatureView - Table scrolling when drawing signature

So I want a signature view within a table cell. Obviously whenever somebody tries to draw in the cell, the table scrolls.
How would I stop the scrolling but ONLY when the user is writing in the signature box?
I found better solution for this issue rather than putting button. Implement the delegate methods in viewController,
class mainVC: UIViewController,YPSignatureDelegate {
Than set delegate of signature view to this view controller
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignatureCell", for: indexPath) as! SignatureCell
cell.signatureView.delegate = self
return cell
}
And then add these code. This are two delegates of YPSignature. Add in Main view controller
func didStart() {
tableView.isScrollEnabled = false
}
// didFinish() is called rigth after the last touch of a gesture is registered in the view.
// Can be used to enabe scrolling in a scroll view if it has previous been disabled.
func didFinish() {
tableView.isScrollEnabled = true
}
I would solve this with a button covering the cell, and when the user taps it, the cell displays the YPDrawSignatureView. Just before the signature view is shown, disable the scrolling:
tableView.scrollEnabled = false
Later when you save the signature, enable scrolling again by setting scrollEnabled to true.
I added a uitableview and custom cells. In one of the custom cells contain a button(ex. addSignatureButton) on the top of signatureView.
I used delegate method to communicate between uitableviewcell and uiviewcontroller. A delegate is added to UITableViewCell to notify whether the addSignatureButton is tapped. Once it is tapped, addSignatureButton is hidden, signatureView is visible and the tableview's scroll is disabled. When user finishes adding signature, signatureView is hidden, addSignatureButton is visible and tableview scroll is enabled.
https://github.com/alvinvgeorge/DrawSignatureOnTableViewCell

What is the best way to implement a custom MKAnnotationView when someone sets a pin using Swift?

When user clicks on a pin, the MKAnnotationView comes up, but it is very limited. I created a custom button but is there a way to customize the entire view that comes up from the pin? Here is what I have so far.
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "location")
annotationView.canShowCallout = true
let btn = UIButton(type: .Custom) as UIButton
btn.frame = CGRectMake(50, 60, 60, 50)
btn.setTitle("button", forState: .Normal)
btn.titleLabel?.textAlignment = NSTextAlignment.Center
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Center
btn.layer.borderColor = UIColor.blueColor().CGColor
btn.layer.borderWidth = 0.5
btn.backgroundColor = UIColor.redColor()
annotationView.rightCalloutAccessoryView = btn
return annotationView
}
You should be able to programmatically construct your own UIViews and assign them to the leftCalloutAccessoryView, rightCalloutAccessoryView, and detailCalloutAccessoryView properties of the MKPinAnnotationView. UIButton is a subclass of UIView, so what you have so far should theoretically work.
If you stick with these 3 properties and play with the frame property for each UIView, you should be able to perform a decent amount of customization. Also keep in mind each UIView can have multiple subviews.
The "Hacky" Solution
If you really want to make a fully customizable callout, you probably need to set up a tap gesture recognizer on the pin itself, which would cause your custom callout view to appear. However, I would advise against this more "hacky" method as it will likely result in the callout being more glitchy. Unfortunately, I don't believe there's a way to directly assign a custom callout view.
Edit: As Rob suggested, you could implement didSelectAnnotationView in your MKMapViewDelegate to spawn your custom callout view instead of a tap gesture recognizer. This is a better but still "hacky" solution-- it would be more glitchy than the stock callout view.

Put checkmark in the left side of UITableViewCell

I want to make something similar to the WiFi settings page: when you tap the table cell, put a checkbox in the left side of the cell, and have a disclosure button accessory view on the right to show more details.
My question: is there a way to put the checkmark in the left side of a UITableViewCell without building a custom UITableViewCell ?
The answer is YES! You don't have to create a custom cell for that or add image views. To simulate checkboxes you only have to prepend a unicode symbol for a checkbox state to the cell text.
The unicode symbols I'm using for checkboxes are \u2705 for checked and \u2B1C for unchecked (nearly the same as \U0001F533 on iOS 5). iOS renders several unicode symbols as icons.
Here are some other symbols:
#"\u2611", #"\u2B1C", #"\u2705", #"\u26AB", #"\u26AA", #"\u2714", #"\U0001F44D", #"\U0001F44E"
Imitating the Wi-Fi settings page (with UITableViewCellStyleValue1):
cell.textLabel.text = #"\u2001 Wi-Fi 1";
cell.detailTextLabel.text = #"\U0001F512 \u268A";
cell.textLabel.text = #"\u2001 Wi-Fi 2";
cell.detailTextLabel.text = #"\U0001F512 \u268C";
cell.textLabel.text = #"\u2713 Wi-Fi 3";
cell.detailTextLabel.text = #"\U0001F513 \u2630";
Of course you can do that :) For example use UITableViewCellStyle
UITableViewCellStyleDefault,
// Simple cell with text label and optional image view
//(behavior of UITableViewCell in iPhoneOS 2.x)
...and put a custom "checkmark" image in that "optional image view".
In Swift you can press Command + Ctrl + Spacebar to show emoticons and special characters or you can copy this ✓ ✔️
So here is a way to do it. Place a UIImageView on the left edge of the cell. Do not set an image so it's blank as a start.
Then, assuming you are doing a custom cell and a class for that UITableViewCell, do something like this:
import UIKit
class MyCustoTableViewCell: UITableViewCell {
#IBOutlet weak var commandOption: UILabel!
#IBOutlet weak var checkMarkImage: UIImageView!
// Sets a left side checkmark on a cell when selected
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.checkMarkImage.image = selected ? UIImage(named: "BlueCheck") : .None
self.commandOption.font = selected ? UIFont(name: "Avenir-Heavy", size: 22) : UIFont(name: "Avenir-Book", size: 22)
// more check mark on the right side
// self.accessoryType = selected ? .Checkmark : .None
}
}
Note the bottom commented out is if you want the checkmark on the right. The super.setSelecdted method fires when a the user has tapped on the table cell. Be sure you have this implemented also:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// do any changes needed here or leave blank if just adding check
}
}
Finally, make sure you have #2x and #3x check mark PNGs assets in your Assets folder. Note those are called "BlueCheck" in this example but use what ever your check mark assets are called.
This approach makes sure that when a user selects a new row the check mark goes away on the current cell.
In this case I'm bolding the text that is to the right of the image view to further indicate it was the selected row.
No. You have to create a custom cell for that.
You should look at the UITableViewCell reference and Table View Guide. Use standard cell style with editingAccessoryType property set to UITableViewCellAccessoryCheckmark.