iOS8 tableviewcell height changing when rotating device in Swift - ios

I am trying to use the new auto size for my tableview. Im doing this:
tableView.rowHeight = UITableViewAutomaticDimension
I have a multiline-uilabel in my UITableViewCell with some constraints that is working splendid; the height of the rows is dynamic when I enter the tableview in both landscape and portrait! Awesome!
... but when I rotate the device the rows get the basic height (i.e. 44).
I added this row:
override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval)
{
self.tableView.reloadData()
}
And the problem vanishes. But should this really be necessary? There must be a better way to fix this?
Edit:
I just found out that the same problem occurs when I'm deleting a row in the table view like this:
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
Am I missing something here? Why aint this working out of the box?
Edit again:
I've now doing like this:
self.tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableViewAutomaticDimension
Then when my data is fetched from API:
self.tableView.reloadData()
self.tableView.beginUpdates()
self.tableView.endUpdates()
This seems to cover all cases I've tested so far, but it seems really hacky! Without the begin/end-updates the cells are displaying some really funky heights at the first load. (But when rotating the device, the cells adjust their heights correctly.)
This all just seems so buggy. I've not found a single guide which cover these cases correctly.

I had a similar issue with rotation where the entire searchbar and tableView were displaced-down on very rotation from portrait to landscape and back. See-> Swift searchBar separates from top of tableView after searchController.active during rotation:
Swift searchBar separates from top of tableView after searchController.active during rotation
I pasted your override function i.e.:
override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval)
{
self.tableView.reloadData()
}
after viewDidLoad function and my problem disappeared. Don't know why. Glenn Tisman

According to the WWDC session from this year, if the cell already uses Autolayout, then it is supposed to automatically resize for you. It would do this by trying to call systemLayoutSizeFittingSize:(CGSize), or if you have not used autolayout, it would try to call sizeThatFits:(CGSize)
On thing to make sure of if you're supporting iOS7 as well is that setting tableView.rowHeight and tableView.estimatedRowHeight will cause strange behavior, and you would want to conditionally call one or the other, but not both, depending on which version of iOS the app is running on.
If you're having issues with the label in particular, you might also check that you're using the new "Automatic Preferred Max Layout Width" attribute for the UILabel (if you're in a storyboard, this is under the "Attributes" inspector) and that lines is set to '0'. See the documentation for more detail. See also "Behavior of Labels" in the iOS Interface Catalog for some caveats about mixing certain behaviors of UILabel and getting strange results.
Finally, you might see what is happening in the newly added rotation methods for size classes:
-willTransitionToSize:withTransitionCoordinator:
-willTransitionToTraitCollection:withTransitionCoordinator:

Related

Swift: Make it obvious that a table view is scrollable

Strange question really but here goes.
I have a table view with some custom cells. On larger devices they all fit and it looks great.
However on the smaller devices like iPhone 4 due to the other content on the page the table view shrinks and therefore not all of its cells are in view.
The problem:
Without actually physically scrolling the view it would be impossible to tell that there were any other cells.
Is there a way around this?
Thanks.
You could use this:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.tableView.flashScrollIndicators()
}
You could use the heightForRowAtIndexPath to calculate a height for the cells so that the last cell is not visible fully. Seeing a cell cut off half way is a good indication for the user to feel that there is more content beneath.
I added this code:
tableView.contentOffset = CGPoint(x: 0, y: 200)
The first card and the last cart are cut-off which gives an impression that you need to scroll.

How to set static grouped TableView cell's width

I am relatively new to Xcode and Swift development and I have a question regarding a UITableViewController with static, grouped cells (on iPad). I want a natural solution to make the cell width not as big as the whole screen.
I have tried this:
override func viewDidAppear(_ animated: Bool) {
tableView.frame = CGRect(x: 175, y: 70, width: view.bounds.width-350, height: view.bounds.height)
}
Problem is that this looks really nasty and gets tricky with navigationbars and tabbars at the top and bottom, but especailly doesn't work properly because it is set at viewDidAppear, so when using the swipe back gesture (like in Settings), the view still appears at full width for a second.
Do you know some other way to solve this issue? Maybe some autolayout stuff, i don't know, I've tried everything I know...
Any help will be appreciated! Thank you!
As you say, autolayout is probably the way to go. If you are using Interface Builder, then you can just set your constraints there. Plenty of information out there to help with that. Here's a good place to start: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html
You should switch to using a regular UIViewController and manually add a UITableView as a subview of the root view. You'll also have to manually set the view controller as the delegate and dataSource of the table view. Then you'll be able to position the table view wherever you like. Unfortunately, you won't be able have static cells - but setting your data dynamically tends to be a better choice in the long run anyway.
The other way to achieve what you want and still use a UITableViewController is by setting it as a child view controller, but this is more fiddly and tends to be more restrictive in my experience.
If you want to manually set frames as in your code example, then you should do that inside the viewDidLayoutSubviews method.

TableView Cells Overlapping UIView After Scrolling Down and Up

I'm playing around with some design concepts and I got stuck with this "bug."
Any idea why is this happening? I've iterated through different things and still can't find the culprit or solution to this.
This "circle" for the price, overlapping the other cell at the bottom of it is my intended design. This is all good, however, when I scroll down and back up, "older" cells suddenly overlaps the "circle."
Kindly see the screenshot. Any help is much appreciated!!!
Has anyone experienced this before?
iOS9 - Xcode 7.3.1
EDIT:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("CategoryCell") as? CategoryCell {
cell.selectionStyle = .None
cell.configureCell(dishes[indexPath.row])
return cell
} else {
return UITableViewCell()
}
}
EDIT 2:
After further analysis, I am quite convinced that this has nothing to do with the height? I played around using different heights but still get the same results.
The thing is, it loads perfectly, even when scrolling down, it's all good. Up until I scroll back up, that's where the problem starts to appear.
Setting the Clip SubViews (Cell) to true will clip everything even on load, so I've set it to false.
The remaining question is, how to handle the clipping when scrolling back up?
EDIT 3:
I think I now understand the problem however, I am still not quite sure how to solve it.
The CircleView is placed on a cell that is meant to overlap to the other cell below it. Settings clipsToBounds, height or putting it infront will have no effect to the cell below it as it goes away from the display when scrolled up.
Anybody has an idea how to somehow redraw this just like it has been freshly loaded (because onload, things are working)? or perhaps is there a clipsToBounds setting elsewhere that I am missing?
I think the solution relates to this: How to stop UITableView from clipping UITableViewCell contents in iOS 7
However, this solution is not working on ios9.
Set the cell layer anchorPointZ to row index in cellForRowAtIndexPath: method
cell.layer.anchorPointZ = indexPath.row;
The issue has to do with the height of your cell. It isn't going to dynamically adjust that for you.
You can try setting the clips to bounds on the tableView (check screenshot)
clipsToBounds option
Have you tried setting an estimatedRowHeight for the tableView? Also, you can use the function heightForRowAtIndexPath and return UITableViewAutomaticDimension. That should automatically dimension every row to fill the circle size.
EDIT: If you want to bring the circle to the front of everything else, try this:
YourLabel.layer.zPosition = 1;
self.view.bringSubviewToFront(YourLabel);

UILabel incorrectly sized in UITableViewCell (Animation after assigning text)

The text in a UILabel is flickering after being displayed, first appearing with ellipsis on a single line, then occupying the 2 lines it fits in.
Notice that the cell height doesn't change.
Here is the problem:
The label "Друзъя, примите участие и наполните Коробку!" (Friends, take part and fill the boxes!) first appears truncated and misaligned as "Друзъя, примите участи..." during the view transition.
This happens only on iPhone 4s with iOS 8.1. All manipulation with Label (except text assigning) happens in the Storyboard.
What is causing this flickering?
Assuming you are changing the test in cellForRowAtIndexPath, and further assuming this does not happen with all strings, only some with certain length, then this is an iOS bug.
See lengthy discussion on this Stack Overflow UITableViewCell post, and a possible workaround:
override func viewDidLoad() {
super.viewDidLoad()
tableView.setNeedsLayout()
tableView.layoutIfNeeded()
tableView.reloadData()
}
Notes
1. I have also noticed that using a small value for estimatedRowHeight such as 20, which is not as tall as the smallest cell, in combination with the doubled reloadData() was also beneficial.
2. You will need to invoke an extra reloadData() prior setNeedsLayout() when changing the cell width, such as toggling tableView.editing
3. A robust alternative to tinkering with a label is to use a non Editable, non Selectable, none Capitalization, noScrolling enabled, no Show Horizontal & Vertical Indicator, no Bounce UITextView.
Exercise this bug, and try out the various workarounds:
► Find this solution on GitHub and additional details on Swift Recipes.

iOS Today Extension Mystery Height

I'm currently working on an iOS Today Extension and I'm having an issue with the extensions height. I've tried from scratch multiple times and I can't seem to figure out where the extra height is coming from. Where am I going wrong with AutoLayout. Thanks.
Storyboard View:
Scene View:
Size Inspector for View:
Results:
I also tried using the following and it said this:
override func viewDidLoad() {
super.viewDidLoad()
self.preferredContentSize = CGSizeMake(0, 100);
}
Edit: Could this be an iOS bug?
I've been beating my head against the desk over this for a while now but I've noticed a repeatable pattern on the simulator as well as a physical device. If I reset contents and settings on the simulator then run the Today Extension on it, it fills the entire space (even though it's not honoring my 100 height constraints), but as soon as I 'stop' running it, the view shrinks to 100 height and there is this extra padding at the bottom. Does anyone else experience this? Is this a bug or is this something that I am causing?
First run, while 'running':
After 'stopping' and subsequent 'runs'
Finally found the issue! Apple has absurd default margins, especially on the bottom. And the only way to change them is to implement the widgetMarginInsetsForProposedMarginInsets method. Here's the swift code:
func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets {
return UIEdgeInsetsZero
}

Resources