I've a TableViewCell with a UITextView, which content is not aligned and cutted at bottom at the first display:
When I scroll down and then up to the top, everything is fine:
My cellForRowAtIndexPath to get the content from a fetchedResultsController is simple:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TextViewCell") as! TextViewCell
let data = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
let text = data.valueForKey("textDu")!.description
cell.textContentView.text = text
return cell
}
How can I get the result after scrolling after start???
Use sizeToFit() after adding content to your textContentView.
cell.textContentView.text = text
cell.textContentView.sizeToFit()
Make sure for sizing cell
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "onContentSizeChange:",
name: UIContentSizeCategoryDidChangeNotification,
object: nil)
tableView.estimatedRowHeight = 89
tableView.rowHeight = UITableViewAutomaticDimension
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func onContentSizeChange(notification: NSNotification) {
tableView.reloadData()
}
Hope it helps you.
In conjunction with #Ashish Kakkad's answer you may want to try to set heightDimensions in viewDidLoad or viewWillAppear:
yourTableView.estimatedRowHeight = 30.0 // Put a real estimate here
yourTableView.rowHeight = UITableViewAutomaticDimension
Use auto layout code to tie the bottom of the cells contentView to the bottom of the text box. When the text box resizes it'll expand the cell with it.
This is in addition to Asish's correct suggestion about automatic cell heights and is quite a high level suggestion as you need to do a few things to get auto layout working right in tableview cells but there's ample examples on that out on the web.
oh, oh. Think I found something. I removed the existing contraints and then I've tried to "add missing constaints". The result was thas the error "Failed to automatically update constraints". Seem's I've a problem with my storyboard-file...
Related
I setup a trivial view based NSTableView, the view is a simple NSTextField used as a label:
func tableView(_ tv: NSTableView, viewFor tc: NSTableColumn?, row: Int)
-> NSView?
{
let v = (tv.makeView(withIdentifier: viewID, owner: nil) as? NSTextField)
?? NSTextField()
v.isSelectable = false
v.isEditable = false
v.stringValue = data[row] // [String]
v.identifier = viewID
return v
}
and then I enable dragging of the items using this delegate method:
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int)
-> NSPasteboardWriting?
{
return MyPasteboardItem(value: data[row])
}
This works, but when I drag the row, I get an empty representation of the textfield:
(in a different setup things like image views and buttons get drawn, but the NSTextField also ends up white).
I highly suspect this is due to the NSTextField being backed by a TextLayer which doesn't get drawn if the tableview captures an image of the view hierarchy being dragged.
What is a good way to fix this? I considered implementing draw(), but well.
Update: If I do an own NSTextField subclass and override draw(), it indeed starts to work:
final class MyTextField : NSTextField {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
}
Looking at the thing in the view debugger shows that the Layer switches from NSTextLayer to _NSViewBackingLayer when draw is overridden.
But I assume this is not exactly desirable? Is there a better way to accomplish this?
Complete sample: https://gist.github.com/helje5/48728983951ab3362af43b967c554475
Setting drawsBackground=false on the textfield fixed it for me.
If you are using xib file then untick "Draws Background" on the Text Field or in your viewFor: method something like:
v.drawsBackground = false;
I ended up with this in an NSTextField subclass, not sure whether it is a good idea:
override public func draw(_ dirtyRect: NSRect) {
// This switches from the UXLabel being backed by `NSTextLayer` to
// `_NSViewBackingLayer`, which may not be desirable.
// BUT: This enables proper drawing of the Drag&Drop cell.
super.draw(dirtyRect)
}
I have a tableview with a label and an image. in some cells, there is no image as i used imageView.removeFromSuperview() to remove it from the cell. When there is an image in the cell, the row height is 445 and "Custom" is checked off.
how can i set the row height dynamically according to how long the label is instead of how long/big the imageview is after i remove the imageview?
If you want dynamic row height, you can define your constraints (making sure they're unambiguous), set the label's numberOfLines to zero, and then in viewDidLoad, tell it that rows should automatically adjust their height:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
If you want to hide/show a UIImageView as well, I must confess that I'm not crazy about the removeFromSuperview approach (because when the cell is reused, you have to re-add the image view, and possibly rebuilding its constraints, too) there are a few options:
You could have a different cell prototype for the cell with the image view and another without the image view. Then cellForRowAtIndexPath just needs to instantiate the right cell.
You could go ahead and define a full set of constraints that are unambiguous for both the presence of the image and without the image. And then, you can activate the constraint and set the image view to hidden as appropriate:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
let image = ... // let's say it was an optional, set if needed, left `nil` if not
cell.customImageView?.image = image
if image == nil {
cell.customImageView.hidden = true
cell.imageBottomConstraint.active = false
cell.customLabel.text = ...
} else {
cell.customImageView.hidden = false
cell.imageBottomConstraint.active = true
}
return cell
}
The trick when having competing sets of constraints that dictate the height of the cell is to just make sure that they have different priorities and/or they use inequality so if both sets are in effect, you don't have an unsatisfiable conflict (e.g. the image view might have higher priority).
You can, if you want, go "old school" and programmatically determine the size of the label field, and then implement heightForRowAtIndexPath, but auto layout makes this process unnecessary.
You need to override this method:
Override func tableview(tableview:UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {}
Return the desired height for the indexPath you want in this method
If you're using UILabel, it has a frame with a height property.
And heightForRowAtIndexPath, should cover what you're wanting for the appropriate method to use:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:
not sure how your image is currently set up, but here's a rough example:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if image != nil {
return 445.0
else {
label.frame.height (or whichever value you'd prefer)
}
}
I try to put a View to the bottom of the screen on my UiTableView. How can I do that? Now it is still the last row. I searched for it but I didnt found someting useful. I hope you guys can help me
Please put UIView below the UITableViewCell like this.
Drag the desired view to the bottom of the UITableView's contents, i.e. below all of the table's cells.
You can add this line inside your code for your table view cell bottom
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 60))
footerView.backgroundColor = UIColor.whiteColor()
return footerView
}
Ive been at this for a while but cant seem to crack it in swift
I want a user to be able to select an image in uicollectionView and for that image to appear in a detailed view controller, i can do this quite easily with a peice of text,
and i can do this when there is a static array of images preloaded. but i cant seem to get anywhere with a collectionview which is loaded with images from a camera.
I understand i need to use
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
}
and this function to isolated selected cell.
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
}
I do have these outlets
#IBOutlet weak var collectionView: UICollectionView!
var images = [UIImage]()
image picker stores all images to this array by
images.insert(newImage, atIndex: 0)
when the array would be passed to the detailviewcontroller, i understand that would have to be copied into another local array and then how would i get the current image that was highlighted to be shown first, perhaps using indexPath.Row
Regards
I'm not using segues, and actually I don't quite understand what your problem is, but I'll try to show you how it could be achieved.
First of all, you have an array with images, so I believe your image should be accessed as images[indexPath.row]
let's suppose that you already have UIViewController class with UIImageView in it.
if so, you can write something like that:
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.presentViewController(myVC, animated: true, completion: nil)
}
for modal or
func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
let myVC = MyViewController()
myVC.imageView.image = images[indexPath.row]
self.navigationController?.pushViewController(myVC, animated: true)
}
if you want to show it as navigational.
I believe that with segues it's basically the same but I think you have to use func prepareForSegue for, you know, preparing the segue (func performSegueWithIdentifier will just perform it). In prepareForSegue you should check identifier of your segue
if segue.identifier == "myIdentifier" {
//your code here
}
and if this identifier is right, put your commands to your myVC there.
I am learning how to use a table based app using Simon NG Swift Programming guide. I typed in the code verbatim and the Xcode environment gets stuck on the let cell = tableView line of code.
Can someone tell me what I am doing wrong?
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var restaurantNames = ["Cafe Deadend", "homei", "teakha", "cafe loius", "petite oyster", "royal oak", "for knee rest",
"jimmy johns", "mickey dee", "daddies big burgers"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return restaurantNames.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell
// configure the cell
cell.textLabel?.text = restaurantNames[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The first error I saw when running your code is this:
2015-02-17 16:28:05.645 delete-me-maps[8008:151860] *** Terminating app due
to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to
dequeue a cell with identifier Cell - must register a nib or a class for the
identifier or connect a prototype cell in a storyboard'
If this is the error you're getting, then you need to add the following to viewDidLoad:
if let myTableView = self.tableView {
self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
Otherwise dequeueReusableCellWithIdentifier does not know what kind of class to use for the cell.
Could you post the error message?
Also, wether the app builds or fails building is not only about the code in your .swift files, it's also about the correct tagging/identifying in your storyboard. Have you made sure you haven't messed up the cell identifiers on your project earlier?
You may simply need to set the prototype cell identifier to "Cell". (Make sure it is exactly the same as in the code).
Go to the storyboard, click on your tableview, click on the attributes.
Give yourself a prototype cell by changing it from 0 to 1.
Click on the prototype cell. Set the 'identifier' attribute to "cell".
I believe that you need to set the Prototype Cell to have the identifier "Cell". You do this by:
Going to Main.storyboard, clicking the cell in the Document Outline, then go to the Attributes Inspector and Type in Cell in the 'Identifier' field.