How to make UITableView content scroll around a central point - ios

I'm trying to figure out how to make the content of a UITableView "centered" around the region contained by the two bars on each side of the screen so that it works on devices of all screen sizes. What I mean by this is:
The initial state of the view should have the first cell inside that region
The table view should be able to scroll until the last cell is inside that region
Cells should not disappear if they're still on screen
I've tried a number of different things around content offsets and insets of the tableview, as well as adjusting the table view's frame, but I inevitably either get the insets wrong or end up with cells disappearing before they're off screen.
I'm wondering if either this is the wrong approach altogether, or I just have the incorrect combination of settings.
Any tips would be greatly appreciated!

The following works for me:
//In viewDidLoad, etc...:
self.edgesForExtendedLayout = UIRectEdgeNone;
self.automaticallyAdjustsScrollViewInsets = YES;
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let inset = (self.tableView.frame.size.height - 44) / 2.0 // Figure out your bar size here
self.tableView.contentInset.top = inset
self.tableView.contentInset.bottom = inset
let path = NSIndexPath(row: 0, section: 0) as IndexPath
self.tableView.scrollToRow(at: path, at: .middle, animated: false)
}

Related

IOS 11: UICollectionView on iPhone X is sized wrong

I have a collection view that the frame appears too tall on the iPhone X. On every other device, the sizing and scrolling works properly as shown below:
However on iPhone X, it looks like this:
The top row is cut off, and it does not scroll all the way down to the last row. Somehow, the sizing correctly calculates the width but not the height, which is about 70 pixels too tall. (I'm not worried about the top and bottom bars. I'll fix those later)
I'm guessing this has something to do with the inset adjustments for the iPhone X screen, but I can't figure out how to fix it. I've tried this in where I size the collection view:
if #available(iOS 11.0, *) {
collectionView.contentInsetAdjustmentBehavior = .always
}
However, I can't seem to fix it.
Edit:
To clarify, the set up for this menu is as follows, there are actually two collection views onscreen. The first scrolls horizontally with paging enabled so that it locks onto each cell. The other collection views are the cells for the first one, and they scroll vertically. We'll call these subCollectionViews.
The subCollectionViews are receiving a size from the original collection view thats too tall. On the storyboard, the collection view's height is defined with respect to the top bar and the bottom paging bar as flush. In the story board, the height of the collection view is about 70 pixels larger than the calculated height during runtime.
So for the cell's layout guide:
override func awakeFromNib() {
cellImage = UIImageView(frame: contentView.frame)
cellImage?.contentMode = .scaleAspectFill
cellImage?.clipsToBounds = true
contentView.addSubview(cellImage!)
}
and for the collection view's layout:
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 8
layout.minimumInteritemSpacing = 8
for the storyboard presets:
I think this is what y'all asked for. If there's anything you need to see, just ask.
I also facing this issue. Need to called safeAreaLayoutGuide for control the size of item.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if #available(iOS 11.0, *) {
return view.safeAreaLayoutGuide.layoutFrame.size
} else {
// Fallback on earlier versions
return view.frame.size
}
}
Add below lines of code. I think it will solve your problem.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.aCollectionVew.setNeedsLayout()
self.aCollectionVew.layoutIfNeeded()
}
Please take all traits, spacing and contentInsetAdjustmentBehavior.
Happy Coding...:)

CollectionView takes a while to appear

I am using autolayout anchors to place my collectionView in my view. In my collectionView, I have a list of users. Since the number of cells is not definite, the height is changed based on the height of the content inside the collectionView. This is what have:
override func viewDidAppear(_ animated: Bool) {
let contentViewHeight = collectionView.getContentHeight() // Returns height of the content of the collectionView
collectionView.heightAnchor.constraint(equalToConstant: contentViewHeight).isActive = true
// I create a height constraint based on the contentHeight
self.collectionView.layoutIfNeeded()
}
This code works great, but the only side-effect is that my collectionView loads in a bit late when the view is shown. Everything else in the view is loaded, and the collectionView just pops up after a while. Is there any way I can add my constraint without causing this issue?
I tried moving my code to viewWillAppear and viewWillLayoutSubviews, but the anchor isn't even applied.

How to set items in collection view go bottom-to-top with swift

I'm making a collection view with fixed height and width and horizontal scroll direction.
At the start I will have 1 cell and I want it in the right side of the collection view instead of the left and when more cells are coming I want them to stack in the right side of the previous cell like 1 - 2 - 3.
I searched for an answer but all similar questions were for objective c.
Any thoughts how could I do this with swift?
Thanks in advance.
The problem is that if you try to set the contentOffset of your collection view in viewWillAppear, the collection view hasn't rendered its items yet. Therefore self.collectionView.contentSize is still {0,0}. The solution is to ask the collection view's layout for the content size.
Additionally, you'll want to make sure that you only set the contentOffset when the contentSize is taller than the bounds of your collection view.
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let contentSize: CGSize? = collectionView?.collectionViewLayout.collectionViewContentSize
if contentSize?.height > collectionView?.bounds.size.height {
let targetContentOffset = CGPoint(x: 0.0, y: (contentSize?.height)! - (collectionView?.bounds.size.height)!)
collectionView?.contentOffset = targetContentOffset
}
}

Why are my UITableViews misplaced on the y-axis when adding them programmatically?

I have as simple setup where I have a view controller embedded in a UINavigationController. On this view controller, I want to display multiple tableViews next to each other (horizontally). I am creating and adding the tableViews in viewDidLoad. It works well except that there is an issue with the y-position of every tableView except for the first one.
When creating the tableViews programmatically, the first tableView is always properly displayed right below the UINavigationBar. However all of the others are displayed "behind" the UINavigationBar even though the y-coordinate is equal to 0 in all of the tableViews.
This is what it looks like when you run it on the simulator (note that the tableView itself has a green backgroundColor):
And this is the code for it:
class ViewController: UIViewController {
var tableViews: [UITableView] = [] // maintained only for debugging purposes
override func viewDidLoad() {
super.viewDidLoad()
let tableViewCount: Int = 5
createTableViews(tableViewCount)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
print(#function, tableViews)
}
func createTableView(count: Int) {
let width = Int(self.view.bounds.width)/count
for i in 0..<count {
let x = width * i
let y = 0
let height = Int(view.bounds.height)
let frame = CGRect(x: x, y: y , width: width, height: height)
let tableView = UITableView(frame: frame, style: UITableViewStyle.Plain)
tableView.backgroundColor = .greenColor()
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableView)
tableView.tag = i
tableViews.append(tableView)
}
}
}
I am only maintaining the tableViews property so that I can print them in viewDidAppear. The console output in viewDidAppear shows that all my tableViews have the same y position on their frames (= 0).
I did find an easy (yet hacky) fix for this. All I have to do is set the first y to 0 and the rest to 64 (which is the height of the status bar plus the height of the navigation bar). Like so:
let y = i == 0 ? 0 : 64
Does anyone have an idea why the tableViews are being misplaced? According to my understanding, all tableViews should be displayed right below the navigation bar, as this is the vertical origin of the view controller's view?
According to my understanding, all tableViews should be displayed right below the navigation bar, as this is the vertical origin of the view controller's view?
This is only the case in my experience if you set myNavigationController.navigationBar.translucent = false. If the navigation bar is translucent, the top of your view is still the top of the screen.
On a side note, you should definitely look into laying these views out via auto layout, rather than this hacky frame math. Would simplify your code a lot.

UITableView scroll to the top of the cell

I have an UITableViewController with 3 static cells. One with the height of 60.0 at the top and one with the same size at the bottom. The height of the mid cell is dynamic and so big, that all 3 cells together fill the whole screen.
The mid cell contains an UITextView which fills the complete cell.
My problem is that when I want to type something in that TextView the tableview automatically scrolls when the keyboard is rising and I don't see the top of the cell including the cursor anymore until I manually scroll back there.
Is there any way I can prevent the table view from scrolling like this automatically? Or tell it that it should scroll to the top of the cell so I see the cursor?
I've already tried to override the viewWillAppear(_:) method without calling the super method of it but then I can't scroll the tableview manually enough so I can't get to the last cell when the keyboard is visible.
I've also tried to scroll manually to the cell inside the textViewDidBeginEditing(_:) but it changed nothing. My method looked like this.
func textViewDidBeginEditing(textView: UITextView) {
let indexPath = NSIndexPath(forRow: 1, inSection: 0)
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}
I've no idea what else I could try so I'd appreciate your help.
Well, you can set the contentInset of the tableView like this:
self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 80, right: 0)
So you can use the bottom to compensate the offsets that you want.
mainTableView.scrollsToTop = true
OR
mainTableView.setContentOffset(CGPointZero, animated:true)

Resources