The bug can be reproduced using the repo here.
I have a strange bug affecting my project in iOS 11 in my UITableView.
The TableView in question is grouped, has expandable cells.
Many weird effects happen that are not appearing on my iOS 10 branch:
Titles superposes
weird teleport issues when content size is above the UITableView container size when the collapsing of the cells occur
Weird teleport to top of tableview at the beginning of the scrolling when content size exceeds the container's size
Cell sizing is wrong (quite often)
There is also a ticket that seems related on the Apple Developers forum here.
I tried without any success:
if #available(iOS 11.0, *) {
tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.never
}
I am trying to find the behavior that changed in iOS 11 that could cause this issue.
Any help would be appreciated!
edit: Clipping to bounds helped (but in the end, it hides/clips the problem). I still have a few issues (2, 3 and 4).
When I try to unwrap a cell it teleports back to the top instead of going smoothly.
When I unwrap a cell and want to scroll to it to it smoothly, it teleports to top then only scrolls to it. (had to add an additional section to show).
Here is a video of the issue (using iPhone 7 Plus, iOS 11, Xcode 9 Golden Master): https://youtu.be/XfxcmmPdeoU
In iOS 11, all the estimated UITableView properties (estimatedRowHeight, estimatedSectionHeaderHeight, and estimatedSectionFooterHeight) default to UITableViewAutomaticDimension.
I see that for your cells that's fine as you're returning UITableViewAutomaticDimension in heightForRow. For your section headers and footers however you aren't utilizing the auto-sizing. I would try disabling all the auto-sizing behavior in your headers/footers by setting estimatedSectionHeaderHeight, and estimatedSectionFooterHeight to 0.
Source: iOS 11 Floating TableView Header
Try this workarround, assuming your IBOutlets and variables are not privates in StandardHeaderView.swift:
func toggleSection(section: SectionType) {
self.sectionsOpened[section] = !self.sectionsOpened[section]!
let sectionIndex = self.sections.index(of: section)!
let indexPath = IndexPath(row: 0, section: sectionIndex)
UIView.animate(withDuration: 0.25) {
self.tableView.reloadRows(at: [indexPath], with: .automatic)
if let headerView = self.tableView.headerView(forSection: sectionIndex) as? StandardHeaderView {
headerView.configWith(title: headerView.headerTitleLabel.text!, isOpen: self.sectionsOpened[section]!, selector: headerView.selector)
}
self.tableView.scrollToRow(at: IndexPath(row: 0, section: sectionIndex), at: .top, animated: true)
}
}
Related
I have screen with two large UICollectionViewCells. Using XIB as Interface Builder. UICollectionView DataSource and Delegate is connected to my UIViewController that contains it.
Installed checkmark is true. isHidden is false. Alpha 1 for cells and UICollectionView. Also I've registered cells for UICollectionView with correct identifiers.
Before I've updated my project from minimum deployment target iOS 13 - UICollectionView works fine. After upgrading to iOS 14 minimum deployment - UICollectionView doesn't show cells. If I return minimum deployment to iOS 13 without any codebase changes - works fine.
Please anyone safe my time as I've wasted whole day already with no luck! Thanks in advance!
So I found the reason of this very strange bug. My goal was to create UICollectionView with cell which contain flexible UITextField. While user is writing - cell changes its size regarding to text height in text field.
To implement it I was using these configurations for my UICollectionView:
Image with UICollectionView configurations
Here You can see that "Cell Size" width is 0, and "Estimate Size" is automatic. It is configured for flexible cell height.
To make it work I have added this code also:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout,
flowLayout.estimatedItemSize.width == .greatestFiniteMagnitude else {
return
}
flowLayout.estimatedItemSize = CGSize(
width: view.frame.width - Size.verticalCollectionInsetsDistance * 2,
// Make the height a reasonable estimate to
// ensure the scroll bar remains smooth
height: 200
)
}
And here is a trick:
When I had upgraded my app to iOS 14 minimum deployment this code is broken. Because, for some reason, when You set "Cell Size" width to 0 and you have iOS 13 minimum deployment, then estimatedItemSize.width == .greatestFiniteMagnitude is true. But for iOS 14 estimatedItemSize.width == .greatestFiniteMagnitude is false and estimatedItemSize.width == 0 is true instead. So now I've fixed my code by adding this condition "flowLayout.estimatedItemSize.width == 0". And here is final version:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout,
flowLayout.estimatedItemSize.width == .greatestFiniteMagnitude || flowLayout.estimatedItemSize.width == 0 else {
return
}
flowLayout.estimatedItemSize = CGSize(
width: view.frame.width - Size.verticalCollectionInsetsDistance * 2,
// Make the height a reasonable estimate to
// ensure the scroll bar remains smooth
height: 200
)
}
P.S. I still don't understand why iOS 14 estimatedItemSize.width is different then iOS 13. If You know answer please describe it in comments. Thanks in advance!
I'm trying to place a table view inside of a basic view controller without any padding on the top and nothing I've tried has worked, no matter what I do there is a gap up top. I placed the following code in my viewDidLoad() for the view controller:
if #available(iOS 11, *) {
tableView.contentInsetAdjustmentBehavior = .never
} else {
self.automaticallyAdjustsScrollViewInsets = false
}
I've gone into storyboard and disabled those settings as well manually:
I do have custom cells I'm not sure if that matters, I do add insetting to the cells but even when I remove that code I have that gap.
Here's the code I customized for my cells:
override func layoutSubviews() {
super.layoutSubviews()
contentView.frame = UIEdgeInsetsInsetRect(contentView.frame, UIEdgeInsetsMake(cellSpacingHeight, 0, 0, 0))
}
I've spent a couple hours googling around and I can't figure it out. I'm using the latest swift and Xcode to build this. I even tried to print the values for the tableView's content inset and it came up as all 0s. Does anyone know why I still have the offset or inset up top in my table view?
Wow okay so I finally figured it out, I had set the table view style to Grouped at some point instead of Plain. Once I made it plain, everything worked, I hope this might help someone else in this position!
I've recently tested my app in iOS 11 and for some reason I'm not able to select one of the first 12 rows in a dynamically populated table view. The didSelectRow isn't even triggered for these rows. The other rows work fine, but even when scrolling down and back up (the cells should have been re-used again by then) the first 12 rows don't work.
Even on a static table view all cells that appear on screen when switching to that view controller will not respond, neither will controls inside them, even when they are in different sections. Cells that are out of screen initially again work fine.
I'll be trying to test this in an app with boilerplate code, but is this a known bug? I couldn't find anything online about it.
I've tested this after updating the devices to iOS 11, then again from Xcode 9 beta 6 without changes to the code, and again after migrating to Swift 4. Same behaviour inside the simulator. Up to iOS 10 everything is fine, only with iOS 11 the problem occurs.
This will break my app for users in two weeks, I need to fix it, so any help or advice very much appreciated!
UPDATE: As Paulw11 suggested, there is indeed another view blocking the rows. This was notable as row 12 could only be selected in the lower part of the cell, but not in the upper part.
The cause for this issue is the following code:
extension UIViewController {
func setBackgroundImage(forTableView tableView: UITableView) {
let bgImage = UIImage(named: "Background Image.png")
let bgImageView = UIImageView(image: bgImage)
tableView.backgroundView = bgImageView
let rect = bgImageView.bounds
let effect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurView = UIVisualEffectView(effect: effect)
let height: CGFloat
switch screenSize.height {
case 480, 568: height = 455
case 736: height = 623
default: height = 554
}
blurView.frame = CGRect(x: 0, y: 0, width: rect.width, height: height)
let container = UIView(frame: rect)
bgImageView.addSubview(blurView)
let bgOverlay = UIImage(named: "Background Overlay.png")
let bgOverlayImageView = UIImageView(image: bgOverlay)
bgOverlayImageView.alpha = 0.15
bgImageView.addSubview(bgOverlayImageView)
self.view.insertSubview(container, at: 1)
}
}
Somehow since iOS 11 this background image seems to be rendered in front of the cells. Not inserting the container view into the table view's view will solve the issue. I've tried setting the zPosition of the container's layer but it does not help. How can I move the background image behind the cells again.
It's weird that this behaviour would change from iOS 10 to 11...
UPDATE 2: Inserting the container at index -1 fixes the issue:
self.view.insertSubview(container, at: -1)
I don't get why this works, though, shouldn't this index be out of range?
UPDATE 3: As Paulw11 pointed out below, the container is completely useless, it was left over from testing and removing it fixes the issue.
The container view seems to be appearing in front of the other views and preventing touches from making it through to the table view.
As an aside, I would see if you can refactor this to use constraints; It always worries me when you see hard-coded screen sizes, as that may break when new devices are released.
I am facing issue with UITableView in Swift. Table contains lyrics. Each cell is a lyric class. I know which index I have to focus on so I show the current lyric in red and the rest in black.
All okay so far. But when using scrollToRow, it's working well before table starts to scroll down to lyrics outside the view. Once the UITableView starts scrolling outside the view, it starts jumping.
Any idea how to make it scroll smoothly to the current cell without jumping?
Here is how I make the table go to the desired lyric:
let lcCell = IndexPath(row: (vc_lyrics.sharedInstance().lyric_time[seconds]?.index)!, section: 0)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
vc_lyrics.sharedInstance().tableView.scrollToRow(at: lcCell, at: .none , animated: false)
vc_lyrics.sharedInstance().tableView!.reloadData()
}
Or if I can keep the lyric cell in the center by scrolling the scrollview of the table, not its delegate scrollToRow.
Change this line to set animated to true:
vc_lyrics.sharedInstance().tableView.scrollToRow(at: lcCell, at: .none , animated: true)
This will cause the cells to scroll smoothly. I would also think about whether or not you need to reload the tableView data here because that can also cause scrolling issues as #rmaddy mentioned.
Im trying to build a scroll within 977 strings of data in the array placed in UITableView , well I'm using the following to do automatic calculation for the
cell height : mytableView.rowHeight = UITableViewAutomaticDimension.
And using the following to scroll to index:
self.mytableView.scrollToRowAtIndexPath(NSIndexPath(forItem: placetogo, inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
Whats happening here is the scroll is taking 16 seconds to scroll to that last index of the array which will be very annoying for the user, when i made the rowHeight = 400 or 300 static value , then it scroll with less than a second to last index.
My cells are different in there heights, so i cannot use the static cell height. I've made a research about it that tableview calls rowHeight frequently to calculate the height.which makes the scroll very slow, is there is any efficient way for that ?
I tried to split my data into 9 or 10 sections but still the same!