I am drawing custom UITableViewCells. My cells are opaque and are completely drawn in the drawRect of the cell to help with performance. I want to handle the look of a selected cell myself. If I don't, then the contents of my cell is covered up by the selectedBackgroundView that is added. Is it common or acceptable to override the setSelected:animated method of my cell so this is done properly. I guess if I did that, then I would not call the super's setSelected method since I would be handling how the cell will show that its selected. I would also have to set the selected property of the cell.
Any help would be great. Thanks.
You can override -[UITableViewCell setSelected:animated:], but you should always call the super's implementation in your implementation. Not doing so could have have unanticipated effects on other selection-related behaviors.
If you don't want the superclass to make any styling changes as a result of the selection, just set the cell's selectionStyle property to UITableViewCellSelectionStyleNone.
Related
As I understand, there seem to be three ways of laying out a custom table view cell:
In Interface Builder.
In layoutSubviews.
In initWithStyle:reuseIdentifier:.
What's the difference between the second and third methods? Also, why not drawRect?
P.S. I'm following Chapter 9 of the book Pro iOS Table Views by Tim Duckett, where we're building custom UITableViewCells. The author shows how to lay out the cell in the same order as above, but I don't know whats the difference between the last two since they both do away with IB. I noticed, though, that the author simply sets the frames in layoutSubviews unlike in initWithStyle:reuseIdentifier: where properties concerning the look of a view are set (e.g., background image, background color, etc.).
You should create your cell subviews in
- initWithStyle: (UITableViewCellStyle) style reuseIdentifier: (NSString*) resueIdentifier
And layout them in layoutSubviews.
-initWithStyle:reuseIdentifier method will be called once at initialization, but you cell may have incorrect frame at this moment.
Thats why you need to layout it in layoutSubviews method, it's called when cell needs to update layout, for example, when autorotation occurs. So if you will layout subviews in this method, you will have valid cell's frame and correct subviews layout.
-[UIView layoutSubviews]
gives you much more control on the way a view is relayout (I suppose in your book example it is done in the table cell contentView).
When you use a NIB file what you do is simply to recreate in memory the view hierarchy with some properties set, but the nib has not the dynamic capability to relayout a cell (or it is limited to the spring/struct or auto-layout capabilities). If you don't use the NIB you must create this hierarchy programmatically.
Especially in a table view cell subclass, you can add to it many properties that could change the way the cell is relayout, e.g. showing a thumbnail image or not, display a certain label or not, and in such cases you probably you need the layoutSubviews method to update the cell layout taking into account all the possible layouts due to different properties values.
So I don't know what the best way to follow MVC is. Similar to the address books app, I want to have a UITableVeiewcell that has the ability to edit notes. I figured I would do that with a UITextView in a UITableViewCell subclass. My subclass has just that as a property, and a label that says "notes". I can see a few use cases that I need to consider,
1) when they are done editing and click outside or hit return.
2) when the text goes beyond the size of the cell I need to resize the cell.
Because my UITextView is in IB, is there a good way to define the delegate methods for the UITextView since my UITableView is in another ViewController subclass? Like how do I pass that information back?
Or, is it better to create my UITableViewCell subclass in code since it's just a couple of items so all my delegate and resizing code is done in the view controller class?
Thanks!
After text field editing was finished, you can store it's value in some dictionary in your controller. You can use cell's indexPath as key in this dictionary. In such way you will not lose your data with dequeue cells.
To resize cell you must call reloadData method and change rowHeight property of entire tableView or implement tableView:heightForRowAtIndexPath: delegate method to set needed row height to current cell.
I haven't use UIKit since iOS 3.1, so the second part of my answer can be out of date, but I hope it will help you =)
I have a custom UITableViewCell completely written in code (no IB), it has an accessory button that simply calls didSelectRowAtIndexPath on the table view, and it works correctly and the method is called without problems.
However, when I tap on the cell itself (not on the accessory view) nothing being called, why ?
EDIT: the code is huge to put here ... however, the custom cell contains a ton of labels, couple images and scroll view ...
This is a shot in the dark, but if each cell has many different objects on it (i.e. images, labels, etc) then it may not be working because those objects are what the user is hitting when they try to click a cell. Does the cell turn blue (indicate selection) at all? If not, try hiding/removing those objects for now and see if it works.
If that is the case, then what you may want to do is create an invisible cell or button that sits on top of the other objects and calls didSelectRowAtIndexPath from behind the scenes.
This should solve your problem:
Raise selection event (didSelectRowAtIndexPath) when subview of UITableViewCell is tapped
Try setting your view's userInteractionEnabled property to NO.
This will make it ignore all touch events, and then the views under it will be able to catch these events. - Felipe Sabino
I'd partially answer my question: the wide scroll view is preventing the cell from calling didSelectRowAtIndexPath, removing the scrollView will solve the problem, however, I want to call this method with the existence of the scrollView ... anyone got ideas would be highly appreciated ...
You must post your code to understand what have you done...You have to check out this example to understand whether your code is correct or not...
http://www.edumobile.org/iphone/iphone-programming-tutorials/impliment-a-custom-accessory-view-for-your-uitableview-in-iphone/
I just need to know is it possible to change UITableViewCellEditingStyle image ?. If possible please tell me How to do that?
I don't see any delegate methods for changing the editing-style view.
You could change the editing button title with the delegate method -tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:, however.
You could also override UITableViewCell and create a custom cell with UITableViewCellEditingStyleNone and a custom editing style behavior and appearance.
In case you're still interested you can actually get this to work by intercepting willTransitionToState and didTransitionToState in a subclass of UITableViewCell. The solution does involve "hacking" around in the cell view hierarchy. Look for the description of recursiveDescription on UIView on how to "dump" a hierarchy, but you will find a UIImageView of which you can change the .image property...
Fairly ugly hack, but does not actually use any private api.
I have a custom UITableViewCell. It has a UIView which is added to the "contentView" of the UITableViewCell. For any update, I'm redrawing that UIView by calling its "setNeedsDisplay" and implementing drawing inside "drawRect" method of the UIView.
The UITableViewCell overrides "willTransitionToState" and according to the bit mask value, asks the UIView to redraw.
Because I'm asking the UIView to redraw itself again, every time I do a "swipe to delete", I see the cell "flicker" a moment; even the text that didn't move position due to the Delete button suffers from a flicker since everything is being redrawn.
I'm aware that a possible solution is not to call "setNeedsDisplay" of the UIView from the "willTransitionToState" but instead call "setNeedsLayout" and have the UIView implement "layoutSubviews".
This is where I'm stuck at: how can I re-layout my UIView since everything inside my UIView is "drawn" (I use "drawInRect" and "drawAtPoint" methods for strings and images). There is also a string on the right side that I wanna hide when the "Delete" button appears (like in the Messages app in iPhone).
How can I do this by doing re-layout instead of re-draw?
Thank you!!!
I think there's an issue with your approach. Rather than draw everything, it's better to set up your subviews in an init method, or in the NIB.
In the willTransitionToState method, update whatever subviews according to the state transition.
In layoutSubviews, update each subview's origin and size as required.
Here's some detail from the willTransitionToState documentation. Although, I'm sure you'd have seen this already:
Subclasses of UITableViewCell can implement this method to animate additional changes to a cell when it is changing state. UITableViewCell calls this method whenever a cell transitions between states, such as from a normal state (the default) to editing mode. The custom cell can set up and position any new views that appear with the new state. The cell then receives a layoutSubviews message (UIView) in which it can position these new views in their final locations for the new state. Subclasses must always call super when overriding this method.