UITableView section index titles too wide for list - ios

Is there a way to increase the width of the section index titles displayed along the edge of a table view? In my current code some of the titles are being clipped on the left and right:
I'm not doing anything special in creating the list, just returning an NSArray filled with sorted NSStrings.

I had the same problem with my section index titles.
Not sure if this is the correct way, what worked for me was adding:
[self.tableView layoutIfNeeded];
before calling
[self.tableView reloadData];
jb

Fixed.
Turns out it's enough to return a single empty string the first time sectionIndexTitlesForTableView: is called, even if the real titles (when the data eventually arrives and the table is reloaded) will be wider.
Only if the initial call returns an empty list does the column for section index titles fail to adjust its width to fit the titles when they arrive.

Reload TableView and it should fix the issue,
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.reloadData()
}

iOS 8
I have that problem in iOS8 too.
This seems to be a bug in iOS8, which is not corrected at the time this post is written (10/2014).
Searching around I found two workarounds.
The first one is to force a reload of the data in the viewDidAppear. This will also correct the problem of self-sizing cells not working on first load.
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.tableView.reloadData()
}
However in my case it was not solving the issue because I used to change the section index titles after viewDidAppear
So the second workaround is simply to realoadData() twice
self.tableView.reloadData()
self.tableView.reloadData()

Related

UITableView section header does not always draw

This is a problem stumping me and my team at work.
We have a header view we are using in one section that is not always drawing. It's inconsistent, though appears to be slightly more frequent on fresh installs.
I will first preempt by stating we are not registering it to the table view and thus not actually dequeueing it. I tried that but the boss says since we are never actually re-using it he is adamant against doing so. Therefore we have it like this:
class DashboardViewController {
...
var trendsHeader: TrendsHeader?
...
override func viewDidLoad() {
super.viewDidLoad()
setupTrendsHeader()
....
}
...
func setupTrendsHeader() {
trendsHeader = Bundle(for: TrendsHeader.self).loadNibNamed(TrendsHeader.identifier, owner: view, options: nil)?.first as? TrendsHeader
trendsHeader?.delegate = self
trendsHeader?.datasource = self
trendsHeader?.leftDropdown.selectRowWithAction(at: 0)
}
...
// in heightForHeaderInSection
return TrendsHeader.cellHeight //Height is returned properly, empty space is of the right height
...
// in viewForHeaderInSection
return trendsHeader ?? UIView()//Should only return UIView if trendsHeader is nil
}
I have tried modifying viewForHeaderInSection as such:
//in viewForHeaderInSection
if trendsHeader == nil {
setupTrendsHeader()//Breakpoint inserted here
}
return = trendsHeader ?? UIView()
And with a breakpoint in the if statement so I should know if the trendsHeader is nil. It doesn't hit the breakpoint but still doesn't draw that header. If I wait anywhere from 5–30 seconds the header will show up, or if I scroll down the header will show up once it redraws the section. But I need it to show up initially as well, which it still does in most runs of the app but sometimes just doesn't. Honestly the most frustrating part is the inconsistency.
Any insight as to why this is occurring and/or a resolution that doesn't involve convincing my boss to register a view for re-use that isn't going to be re-used?
We found it. Long story short, the section in question is tied to 2 service calls, one for each option on the header's drop down menu. Those services had delegates who reloaded the section upon the callback functions, and they were getting them in quick succession causing the glitch.
We replaced the reload section code with reload rows code instead, so the header does not get refreshed.

Switch calls multiple cases one after another when checking table view tag

I have a collection view with three different cells. Each of the cells contains a table view. So, there are three table views. I've set tags for each of them (from 1 to 3).
Now, on my view controller (I set it as the table view's data source when I dequeue collection view's cells) I call table view's data source method for the number of rows. To distinguish table views I check each one's tag. Here is the code for that:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch tableView.tag {
case 1:
if unitItems1 != nil {
return unitItems1!.count
} else {
return 0
}
case 2:
if unitItems2 != nil {
return unitItems2!.count
} else {
return 4
}
case 3:
if unitItems3 != nil {
return unitItems3!.count
} else {
return 4
}
default:
return 0
}
}
The problem is, when the first cell of the collection view is shown (with the first table view) it works fine. But when I scroll to the second cell, BOTH case 2 and case 3 get executed. After that, the second table view shows data as expected, but when I scroll to the third one, the method doesn't get called.
I can't figure out why two case statements get called one after another, while everything works fine for the first cell. If you have any ideas why this happens (or maybe, you could suggested a better way of checking table view's), I would appreciate your help.
Actually, the solution is quite simple. The reason of the problem was that collectionView's data source method was dequeueing all the cells one after another, even when they weren't on the screen. Consequently, tableView's inside of each cell were getting set, too. So, their data source method was getting called, hence the problem.
UICollectionView has a property called isPrefetchingEnabled. According to the documentation it denotes whether cells and data prefetching is enabled.
The documentation says:
When true, the collection view requests cells in advance of when they will be displayed, spreading the rendering over multiple layout passes. When false, the cells are requested as they are needed for display, often with multiple cells being requested in the same render loop. Setting this property to false also disables data prefetching. The default value of this property is true.
So, to solve the problem, described in the question, I set it to false as soon as my collectionView gets set.

Refresh Control Issue with custom cells - Swift 4 IOS 11

I am building an iOS app and I am trying to implement a pull-down refresh control on my project. The data is fetched correctly from an API and displayed on my table. But the problem rises when I do pull down to refresh. The following situations happen:
If I pull down for a long distance from the top, and the tableview.reloadData() function is called, the cells in the non-visible portion of the table come with the default tableview cells on top of them, overlapping...
if I pull down multiple times in quick succession the same issue happens.
I believe that it is because tableview.reloadData() is called multiple times in quick succession. But why are the default cells getting dequeued on top of my custom cells? Here is the section of code in the function to handle the pulldown:
#objc func refreshFunc(){
//let offset = scrollView.contentOffset.y
if myRefreshControl.isRefreshing{
readJson { (activities) in
self.activities = activities
self.tableView.reloadData()
self.myRefreshControl.endRefreshing()
}
}
}
Any help would be appreciated. Thanks in advance
UPDATE:
Changing the code to the code below seems to remove the error, but the problem is that now I need to pull down twice in order to get the results updated on the table:
#objc func refreshFunc(){
readJson { (activities) in
self.activities = activities
}
self.tableView.reloadData()
self.myRefreshControl.endRefreshing()
}
Please note that running the reloadData on the main thread gives the same result, I still need to pull down twice to update.
Please try to give some delay before refresh table view may it resolve your problem.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayTime) { [weak self] in
self?.tableView.reloadData()
}
Hope it works
Cheers :)
DispatchQueue.main.async {
self.tableView.reloadData
}
Try this, always, if u want change UI you have to call on main thread

UICollectionView does not scroll after it has been initialized

I have a subclass of UICollectionViewController that is nested inside a UINavigationController. The collection contains several cells (currently, 3) and each cell is as big as the full screen.
When the whole thing is shown, the collection view initally scrolls to a specific cell (which works flawlessly for each cell):
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let path = currentlyPresentedPhotoCellIndexPath { // this is set in the beginning
collectionView?.scrollToItemAtIndexPath(path, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: false)
}
}
However, the collection view refuses to scroll horizontally, hereafter, as if the user interaction was disabled. I am not sure what is happening, but this is what I have checked so far:
user interaction is enabled for the collection view
the next cell (right or left, depending on the scroll direction) is requested correctly which I found out by inspecting collectionView:cellForItemAtIndexPath:
the requested imagePath is the right one
scrollToItemAtIndexPath... does not work either if I try to trigger a scroll programmatically after everything has been loaded (nothing happens)
scrollRectToVisible... does neither
setting collectionView?.contentInset = UIEdgeInsetsZero before the programmatic scroll attempts take place does not change anything
the content size of the collection view is 3072x768 (= 3 screens, i.e. 3 cells)
Which bullet points are missing, here?
Although the post did not precisely tackle the root of my problem it forced me to ponder the code that I posted. If you look at it you will see that it basically says: Whenever the views need to be layouted, scroll to the cell at position currentlyPresentedPhotoCellIndexPath. However, and this you cannot see without any context, this variable is only set once, when the whole controller is being initialized. Thus, when you try to scroll, the layout changes, the controller then jumps back to the initial cell and it looks like nothing happens, at all.
To change this, you just have to enforce a single scroll, e.g. by doing this:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let path = currentlyPresentedPhotoCellIndexPath { // only once possible
collectionView?.scrollToItemAtIndexPath(path, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: false)
currentlyPresentedPhotoCellIndexPath = nil // because of this line
// "initiallyPresentedPhotoCellIndexPath" would probably a better name
}
}
A big thanks to Mr.T!

UITableViewCell overlapping issue

Hello
Now I've been trying to display html links in a UITableView.
I've been trying to do this via adding instances of UITableViewCell to the tableview's subview.
func updateViewController(){
for name : String in currentDirectoryNames {
var pusher = UITableViewCell();
pusher.textLabel?.text = name;
listView.addSubview(pusher);
}
}
Sadly the result ends up with the text overlapped in one row :(
It looks like this...
Any ideas?
That's not how UITableView works, at all. I highly suggest you read Apple's documentation on TableView Programming. At the very least, you'll need to set your view controller as the dataSource for the table view and implement the -tableView:numberOfRowsInSection: and -tableView:cellForRowAtIndexPath: methods.
The func you're calling is adding all of your subviews with origin.y equal to 0 (which makes them look like they're all on top of each other). You may have to do something like set pusher.frame.origin.y to dynamically calculate based on which cell is being added.

Resources