Swift: Make it obvious that a table view is scrollable - ios

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.

Related

Have autolayout CHANGE the height of a cell, already on screen, in a dynamic height cell table?

Nowadays fortunately it's trivial to have an iOS table where every cell has a dynamic height. So in the cell vertical constraints ..
---- top of content view
- vertical constraint to
-- UILabel, with, .lines set to zero
- vertical constraint to
---- bottom of content view
Assume the UILabel texts vary greatly one word, 20 words, 100 words,
In the table set
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200 // say
and you're done, these days it works perfectly of course.
However, I had the common situation where you load the table, imagine ten cells.
I populate the UILabel with "Loading..."
Only then - say, a second or two later - do we get the information for the text content. It arrives say a second later and the cell changes the text to "Some long text .. with many lines".
In fact I was surprised to learn it seems UITableView does NOT handle this. The cell in question gets stuck on the original short height.
So, after the larger text is set, I tried all permutations of the usual:
maintext.sizeToFit()
contentView.layoutSubviews()
contentView.layoutIfNeeded()
on the cell, doesn't work.
I tried sending a setNeedsLayout and/or layoutIfNeeded to the table itself, doesn't work.
I thought about .reloadData() on the table itself but - doh - that would again trigger the content being drawn from the server and loaded again, so that's not ideal.
Please note that:
Obviously there are any number of workarounds for the specific example such as not using dynamic data
I am completely aware how to manually animate the height of one cell (like when you "expand" one to show something else when the user taps)
This question is about autolayout and table view - which, thanks Apple, nowadays flawlessly handles completely dynamic cell heights involving UILabels with lines zero.
But what about if the text in such a label changes?
It seems that the table view system does NOT handle this.
Surely there's a way?
When the content of a cell changes the layout (in this case, the height) you must inform the table view that the layout has changed.
This is commonly done with either:
tableView.beginUpdates()
tableView.endUpdates()
or:
tableView.performBatchUpdates(_:completion:)
Why is that not triggered automatically?
I suppose it could be to allow you to do your own animation, or you may want to delay the update, or some other reason that doesn't come to mind at the moment.
Or, it may be due to maintaining backward compatibility?
I don't know. I imagine Apple could tell us...

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.

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.

Table View resizing issue

I am developing an app that will have a small login screen. I used a table view that calls separate nib files. Each nib file is set to have a 100 row height and the entire table (3 rows) has a a height of 300. It seems to not work well depending on the size of the iPhone. In the following screenshot you can see there is still white space added after the last row. How could i adjust the table view as a whole to be the same size as all 3 of the table view cells? I could adjust it so it works for this one iPhone screen but it will not look good for others. I am using swift to code if that helps.
Thanks!
You can achieve this by getting the Iphone models screen size and divide in to / 3. You use like this in the view controller :-
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = self.view.frame.height / 3
}

iOS8 tableviewcell height changing when rotating device in Swift

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:

Resources