TableViewCell with SegmentControl - ios

I have tableview in which a particular cell has the UISegmentedControl in it.
My doubt is when a particular segment is selected I need to expand the cell and show the information below and need to hide it when the other segment is selected.
For Ex:
I have three segment A, B and C. When selecting the segment B, I need to show switch below the segment and when the other two segments are selected nothing must be displayed below the segment.

Your dataSource's objects should have an "extended" property.
Each time a segmentedControl is changed, update your dataSource accordingly and reload your cell.
When you configure your cell, change its size depending on the "extended" property of the object.

Theres a few things to do here. You need to make sure your tableview is using automatic dimension for its cell height. Dont use the -heightForRowAtIndexPath method (remove it). Instead set two properties on the tableview :
[self.tableview setEstimatedRowHeight:110];
[self.tableview setRowHeight:UITableViewAutomaticDimension];
This enables proper autolayout (in case you havent already) for each cell.
You will need to have a subclass of UITableViewCell in code, if you havent already (sorry for skipping over some quite big things!). Add the information label to your cell in Interface Builder. Give it a height constraint, and then drag this height constraint into your cell subclass so you can change it.
Now put your code for handling the segmented control in the subclass. When you detect that the central segment has been selected, then affect the height constraint of your information label, like this :
self.labelHeightConstraint.constant = 40;
You may also need a call to setNeedsLayout :
[self setNeedsLayout];
Apologies for the brevity - hopefully this will point you in the right direction. There are some other details - for eg on -prepareForReuse method (on the cell) you can set the height of the info label to 0 (and call setNeedsLayout again).

Related

Disabling touch interaction of Spaces between Custom table view cell

I use custom cells of subclassing UITableViewCell in a table view. And There must be space between cells. I succesfully add the space with adding a subview that I called SpaceView into the content view. But When I touched the spaceView, it is perceived as I touched the cell. And didSelectRow method called. I tried to set spaceView's UserInteractionEnabled==NO. But It doesn't work.
So my question is; Is this the right way I used to add space between cells ? Should I try to add cells for making the space ? or If its the right way, How can I prevent calling "didSelectRowAtIndexPath" method when I touched spaceView ?
like Inder said below, u can use an UIButton to solve the issue.
1) in your custom cell: at the bottom of your custom cell add a blank UIButton with the height u actually need between cells, and customize its background color according to your needs.
2) in cellforrowatindexpath: disable button of each cell. (or you can also do that in Interface Builder of previous step)
result: u have a clear disabled button that will appear as required space between cells.
Make your spaceView as UIButton (I guess it's UIView right now)
When you add UIButton that touch will be consumed by the button thus touch won't be passed to it's parent.
OR
I'm not sure if it will work or not, you can add tap gesture to your spaceView

Hide UITableViewCell from VoiceOver

I have a static UITableView with various cells in it. I need to hide/show some of those cells, so I've implemented heightForRowAtIndexPath and return 0 when appropriate in order to hide the right cells. This works great for sighted users, but for those who use VoiceOver those elements are still highlighted and accessible when they should not be. How can I ensure those UITableViewCells are no longer accessible when I change their height to 0?
I've tried setting the cell to not be an accessible element as well as setting the elements to be hidden but this has no effect on it. The cell has not been subclassed - it's just a UITableViewCell. I have not set anything in regards to accessibility on the cell nor the cell's contents (textLabel, detailTextLabel).
Doesn't do the trick:
self.cellToHide.isAccessibilityElement = NO;
self.cellToHide.accessibilityElementsHidden = YES;
Update Cell VoiceOver Elements By Reloading Cell(s)
After reading about a UITableView taking control over Accessibility elements and observing apps that have similar features, I figured that a TableView must update its Accessibility information upon loading or reloading a cell. I tried forcing the cell to reload after changing its Accessibility properties and that solved the problem. VoiceOver information was updated.
The following is an example of code that runs when the cell in question is tapped. Alternatively, it could run when some other event requires that VoiceOver elements are updated.
// Make changes to accessibility properties such as
cell.isAccessibilityElement = false
cell.accessibilityElementsHidden = true
// reloadRows() allows VoiceOver to update its element list for the related cell(s)
// "indexPath" is for the desired row
// reloadRows() expects an array of IndexPaths so an array of one is created inline
tableView.reloadRows(at: [indexPath], with: .automatic)
// Calling UIAccessibilityPostNotification() is not necessary to realize the VoiceOver changes in the TableViewCell
Background
I wrestled with this problem for a while before finding a solution. In my case the TableView cells are created in code. There are no storyboards or nibs involved. However, this solution should work regardless of how the TableView was constructed.
I have custom, subclassed TableView cells with view hierarchies built in code and added as a subview of the UITableViewCell's contentView. I assumed I could modify the isAccessibilityElement and/or accessibilityElementsHidden properties of various subviews and call UIAccessibilityPostNotification() to realize the VoiceOver changes as I have done outside of TableView's. These changes were not recognized by VoiceOver, only the accessibility state the cell was in when it was loaded was recognized.
For the cell I wrestled with, the height dynamically changes to accommodate a DatePicker that is shown and hidden on cell tap. I only want the DatePicker visible to VoiceOver when it is visible on the screen. I try to avoid reloading the TableView, Sections or Rows to make dynamic changes if at all possible. If I have to reload, I try to make it as isolated as possible (reload one cell or one section not the whole TableView). In this case I did not need to reload anything to make the cell expand to reveal the DatePicker so it did not occur to me try reloading the cell for Accessibility updates.
Related Information: UIAccessibility API Reference on Apple's web site
Try adding below code after you set accessibilityElementHidden.
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, yourTableView);

Grouped TableView cell width

In iOS6, I cannot seem to get the width of the cell in cellForRowAtIndexPath for the grouped table style. Logging either the frame or the bounds for either the cell or its contentview returns 320 - even on iPad. I need to determine the cell width programmatically for any device as I need to calculate text sizes. Any advice in getting the correct cell width for a grouped tableview in cellForRowAtIndexpath would be appreciated please
The method you're using is the wrong place to calculate any kind of view-related constraints. The -tableView:cellForRowAtIndexPath: method is part of the table view's data source, not its delegate. You cannot rely on the frame or anything else here to be meaningful, it's meant as the place to configure the cell's /data/.
If you need to make calculations to view frames and such, and you're not using a custom subclass of UITableViewCell (i.e., you're just adding views to a default instance of UITableViewCell or configuring stock views), you would set up any frame-related / view specific attributes in the /delegate/ callback -tableView:willDisplayCell:forRowAtIndexPath: method. This is the place to configure any of the visible/view-related properties of your cell, and you will now have accurate layout information for the cell (its bounds will be correct, any layout/configuration of internal views will be complete, etc.).
If you have a custom subclass already, you can either do your view related property configuration in the delegate callback above, or you can do it in UIView's -layoutSubviews method, depending on your exact needs. For more information, see the documentation for -tableView:willDisplayCell:forRowAtIndexPath:.

UITableViewCell frame height not matching tableView:heightForRowAtIndexPath:

I'm constructing a UITableView with variable height custom table cells, their height determined by the size of a contained multi-line UILabel. I've got the tableView:heightForRowAtIndexPath: delegate method wired up and calculating the final height correctly using sizeWithFont:constrainedToSize:.
I've run across strange issue: by the time the data source method tableView:cellForRowAtIndexPath: is called, the correct per-row height has already been determined as described above, but the frame of the cell does not match that height. Instead, the frame.size.height property of the cell is the default cell height of the table view (86 px, as I've set it in Interface Builder, the correct height when the contained UILabel has just one line of text), instead of being the height that tableView:heightForRowAtIndexPath: determined correct for that index path.
I'm producing the cells in cellForRowAtIndexPath: using dequeuing, that is,
// Using storyboards, this never returns nil, no need to check for it
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"SomeIdentifier"];
NSLog(#"%f", cell.frame.size.height); // 86, not correct if the cell contains a multi-line UILabel
It seems, then, that whatever iOS is doing behind the scenes, the dequeuing is not setting the frame property of the cell to match the calculated height. This in itself is not that surprising, dequeuing concerns itself with cell instances, not their geometry. The cells are rendered correctly, though, so the height property is being set somewhere, but it happens after cellForRowAtIndexPath:.
So: when I initially populate the table view, cell.frame.size.height is 86 for all the cells as they appear for the first time when I scroll the list downwards. Since the correct geometry is set sometime after the first cellForRowAtIndexPath: for each row before it's displayed, when I scroll back up, the height property is correct for each cell that comes back into view after being reused.
After this I can scroll the table view back and forth at will, and the height property remains correct for each cell from that point on.
What's the correct way of getting the correct cell height the first time around, before any dequeue-based reuse happens? I need this to do a bit of re-positioning of the subviews of the table cell. Do I need to manually call heightForRowAtIndexPath: in cellForRowAtIndexPath: and then manually set the frame of the freshly created CustomCell instance to match that height? This seems redundant, and I'd need to create a mechanism to detect when the cell is created for the first time with the wrong frame height vs. when it is dequeued with the correct frame height later to avoid this redundancy.
So, if someone can shed some light into what the logic is behind this, I'd appreciate it.
As suggested by Flexo, answering this myself is apparently better than adding an edit to the question. So, here's the previous edit as an answer:
Nevermind, I should read the docs better. I can get the correct frame in the tableView:willDisplayCell:forRowAtIndexPath: method of UITableViewDelegate, so that is the correct place to do subview customization that relies on the correct frame being set, not cellForRowAtIndexPath:.
Interesting that the docs say this, though:
After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out.
...since the correct frame is already there when this delegate method is called. But anyway, problem solved.
Don't forget that the cell is a UIView, so overriding layoutSubviews is also a valid way to get the correct frame and adjust size/position of subviews. Just don't forget to call [super layoutSubviews].
Easiest way I found was just to call cell.layoutIfNeeded() before you do any setup on the cell. This makes sure all the layout constraints are calculated and the frames are set.

How to avoid cells background image from hiding the separator line between rows

In my table view I am using custom image for the UITableView cell's background. It works perfectly except for the fact it hides the row separator. And now there is no row visible.
Is there a way to increase the distance so that cells will get separated.
Please help!!!
Thanks,
Without seeing what you are seeing, it's a bit hard to tell. That said, you could try adding the separator to the image so that it shows up in the cell.
If you want to change the height of the cell, implement the -tableView:heightForRowAtIndexPath: method in the table view delegate. Just return the correct height for the row at indexPath. I believe there is also a way to set the rowHeight in the table view properties in interface builder if all cells will be the same, but I tend to stay away from IB when possible.
As far as my knowledge you can add a line image to the cell as a footer.So that you can see the separator
I believe you have to override the -setFrame: method in your custom cell and return the same frame with height minus 1 pixel.
Also be sure to call [super layoutSubviews]; in your -layoutSubviews method if you have overridden this method with some custom implementation.
LineSeparator may be invisible to you because of your background image in your cell. Try to change the style of your separator.
Alternative Way:
Otherwise You have to add a one pixel line to the bottom of your Custom cell background image by your designer and if it's still not visible in your tableView, then you have to increase a height for your cell in heightForRowAtIndexPath: method.
Make sure your view if you have one that is inside your Cell is exactly the same size as your cell's size.
Make sure:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
is setting your cell heights correctly for all cells.

Resources