I have an NSTableView with some cells that where the value of enabled is set through bindings. I want to be able to change the colour of the cells depending on whether the cell is enabled or not. Previously I have done this through the NSTAbleView delegate method tableView: willDisplayCell: forTableColumn: row: which up until now worked fine. I've had to switch off the table delegate though and so I need to find another way to do it. I suspect it's a problem with an obvious answer, but how do I access each cell in the table? I can get the number of rows and columns in the table, and I can cycle trough them, I'm just not sure what method to call to get the cell in column i, row j.
Generally speaking, you shouldn't be cycling through the rows and columns. Your code should be able to do the right thing, given any row or column.
One way to do it is to write your own cell class and implement the appropriate drawing and highlighting methods that you'll find in the NSCell documentation. You'd implement
– drawWithFrame:inView: and probably -highlight:withFrame:inView:
Yet another way is to subclass NSTableView, and override -preparedCellAtColumn:row: to do whatever manipulation of the cell you want just before it's drawn.
The easiest way to do what you want though, is to just use the delegate method as you were before. Why don't you want to do it that way?
Assuming you don't want to color an entire column, the easiest way is tableView:willDisplayCell:forTableColumn:row:, since there is only one cell per column (the view uses the same cell for that column in every row).
Why did you get rid of your delegate?
Related
I want to make a custom text selection in my table view.
I found this awesome answer on how to set the colors, fonts, etc. of the cells.
However, there is one issue.
It does not work for group rows. I see that the method gets invoked, but I think the style gets overwritten somewhere in either the NSTableCellView, or in the NSTableView class.
How can I fix this?
EDIT
It's a view based NSTableView
Is there a way to display a different small image (icon) for each row of a NSTableColumn ?
I don't necessarily need to add a new column for it, I was wondering if I can just add the icon in front of the text of each row.
I know there is the method: - (void)setDataCell:(NSCell *)aCell . However this method seems to use the same cell for all rows, which is not what I want.
Is there a solution to this problem which doesn't require to subclass the NSTableColumn ? If not, what should I subclass ?
thanks
Make the cell for the column in question an NSImageCell. You can do this in Interface Builder by dragging an "Image Cell" from the object library onto the column. Then select the column and you'll be able to bind to an image source via one of the Data, Value, Value Path, or Valueurl bindings. Which one you choose depends on whether the source property in your model returns NSData, NSImage, NSString path, or NSURL url, respectively. See the documentation on NSImageCell bindings for more complete information.
Cells are the same for each row, because they're a lightweight class used as a performance optimization for drawing. That doesn't mean that each row has to use the cell to draw the same image though, any more than the text columns' cells have to draw the same string for each row.
If you really need the image to be in the same column as text, you'll have to do something more like duDE explains. Off the top of my head, I believe bindings should be still possible in this case, but you'll have to write more code to make that work. Rather than do that, I would probably switch to using a view based NSTableView, which makes putting multiple views in a single column/row easy, and will let you continue to use bindings without any extra work.
EDIT: duDE's answer was deleted, but to summarize, it suggested creating a custom NSCell subclass that would draw both an image and text.
I know this question had been asked hundreds of times before, but it's never really been solved (Or at least the way I'd like it to be). I have a rather complex UITableViewCell setup. The cell.backgroundView is loaded from a UIView subclass which uses a fair bit of CoreGraphics and CoreText. The code is rife with CTFramesetterSuggestFrameSizeWithConstraints, so I'm relectant to duplicate the class in the heightForRowAtIndexPath method.
I think I can solve this by creating an NSMutableDictionary with the indexPath as the key and the height as the value. But then I'm faced with the problem of heightForRowAtIndexPath being called first. I believe I can solve this problem by guessing the height of the cell and then once the cell's UIView subclass has finished rendering, use delegation to set the cell's height.
But this leaves me with the problem, how the hell do I delegate this? And, how to I prevent scrolling from being extremely choppy? as the cells will be created and resized in a split second.
In the past, I've used a dummy cell. I have a separate method -fillInCell:forRowAtIndexPath: which puts data into the cell. That way I can fill out the dummy cell in -tableView:heightForRowAtIndexPath: and the real cell in -tableView:cellForRowAtIndexPath:.
If this does not work for you then there are other options.
The first thing that comes to mind is create real cells in -tableView:heightForRowAtIndexPath: instead of -tableView:cellForRowAtIndexPath:. You can store completed cells in a mutable dictionary. -tableView:cellForRowAtIndexPath: will simply pull the completed cell from the dictionary. You should also detect when scrolling has stopped so you can empty your dictionary (just because -tableView:heightForRowAtIndexPath: was called doesn't mean -tableView:cellForRowAtIndexPath: will get call for the same indexPath).
Hope that helps.
Is there a way to make table view not recycle UITableViewCell so after all cells are loaded, it won't ask for cells(ie tableView:cellForRow...)?
I know I can put the table view in a scroll view and make the table view to have the same size as the scroll view, so all cells will be loaded, but some of my cells have variable sizes, then I need to update the scroll view's content size after the cells' sizes are changed.
Is there any other way to do this?
update:
Sorry for the misleading, actually I mean how to make it not REMOVE cells once created, so if there are ten cells, and there won't be any cell returned by dequeueReusableCell and after ten tableView:cellForRow: it won't call it again.
Simply not use reusable identifier will make it create new cell every time as needed, even the cell at position 1 has been created but then reused for position 2.
Set the reuseIdentifier to nil.
This is much better than using a different identifier for each cell, as the table can now dispose unneeded cells quickly. If they have some identifier set, there's no way to tell if you will ever reuse them.
So you don't have to miss the reuse part completely, just for the cells you don't want to. If the new cell contains the same subviews (maybe just layout and configured differently) - it might still be better to reuse.
Just don't use a cellIdentifier, or use a different identifier for each cell.
just dont use - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
in the cellForRowAtIndexPath method and create a new cell everytime.
Other way is to give a different cell Identifier for each cell you create.
Now, If you can elaborate on why you dont want the tableview to recycle its cells (which is one of the powerful feature of tableview), may be you can find out other ways to achieve the same thing with reusing the cells..!!
Hope it helps..:)
We have a scenario where we reuse the same UITableView to display different sets of records from the database as a user selects an item in a different UITableView (similar in concept to a splitviewcontroller, but all in the same view).
When the user selects a different area to view, we fetch the appropriate records from the database, update the Source with the new set of records, and call ReloadData.
The problem is that some of the cells in the UITableView still exist and are reused when switching between lists, resulting in invalid or overlapped data for various rows.
The question I have is: is there a method whereby we can tell the UITableView to discard all existing cells including those queued for reuse? I would have expected ReloadData to perform this task, but it does not.
Update with additional clarification:
Each cell in our table is composed of a variable number of subviews (we are trying to mimic a grid control). When the user selects a different list in the left-hand navigation, there is no guarantee that the subview positions (columns) in the newly selected list will overlap with those in the previous list. This is why we are looking for a method to remove the queued cells.
Since this is a situation that others may find themselves in, I will post the solution that we used, but am still interested in more "native" ways of doing this.
Here is how we solved the issue:
When the set of records being displayed is changed, we update the UITableView with a unique identifier for the current cell configuration (i.e. which list of data is the user currently viewing).
We then created a custom version of UITableViewCell and record the unique list identifier in the cell when it is created.
When we dequeue a reusable cell, we compare the view's current unique identifier with the unique identifier stored in the cell and, if they don't match, we discard the cell and create a new one.
Hopefully this will help someone down the road.
ReloadData does not clear the re-use queue. It simply triggers the callbacks to re-read the data which reloads the rows. As each cell get's loaded, if you're getting it out the re-use queue it will still be used. That's good even if the table view is re-used because the cell types are the same type especially since you use the CellIdentifier to ensure that.
But, it's kind of odd that you're overlapping data. When you get a cell out of the re-use queue, how are you putting the data in it? Are you painting the data directly on the cell? Are you adding subViews with the data (causing multiple sets of overlapped data)? Typically, a cell contains subviews like text labels and the data is set on them so there's no scenario where data gets overlapped - the subviews of cell just has their data updated ...
Your GetCell method needs to ensure that a dequeued cell is fully configured with the new data that it is going to display.
A common mistake is assuming that just dequeuing the cell for display will give you a fresh cell that you can use.
If you have done any customization with your cell, like adding views, modifies its properties (images, disclosure indicators, background colors) you must make sure in the GetCell method that is reusing a cell that every single one of those properties is properly set before returning the cell.