I have a UIPageViewController which contains UICollectionViewControllers who's collectionView'scontentInset that need to be adjusted. For various UI-layout reasons, I only need the contentInset on these UICollectionViewControllers when they appear in a UIPageViewController. Below is my attempt to adjust the contentInset for the collectionView.
self.viewControllers = [ ViewControllerA(), ViewControllerB(), ViewControllerC()]
for viewController in viewControllers {
if let vc = viewController as? UICollectionViewController, collectionView = vc.collectionView {
collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: bottomContentInset(), right: 0)
}
}
The problem that I am encountering is that only the first view controller(on the first page) gets the contentInsetadjusted, is there a better way of doing this
Not sure if you solved this, but this may've been occurring because only the visible collection view's cells (in ViewControllerA) were dequeued. The collection views' cells in your other VCs possibly hadn't yet been dequeued, or it's possible the other VCs themselves hadn't yet been initialized (not sure how you instantiate the VCs). I would either use the UIPageViewController's delegate methods to set each collection view's contentInset property, or try it in the viewWillAppear: method of each VC.
Related
I am experiencing issues with setting contentInset on a tableView behaving inconsistently, depending on when it is called. I am using the following:
let edgeInsets = UIEdgeInsets(top: 52, left: 0, bottom: 0, right: 0)
tableView.contentInset = edgeInsets
tableView.scrollIndicatorInsets = edgeInsets
The top value is hard set to 52 there for testing, but in practice will be calculated from another view.
I am doing this because I need to have a view pinned to the top of a table view controller.
The behaviour I am experiencing is that if I use that code in the viewDidLoad or viewWillAppear functions, it works as I would expect. The tableView is below the pinned view and scrolled to its top (so all its content is visible). However, at that point, the pinned view has not been laid out, and its height is 0, so I can't use it to correctly set the top of the content inset (hence the hard 52).
If I use the above code from the viewDidLayoutSubviews function, which is where I have had it the whole time, it does not have the same results. The insets are actually set, but the tableView is also scrolled that much down, hiding its top rows behind the pinned view. I can then scroll up to see the top cells, and the tableView is then inset under the header, but it shouldn't start scrolled like that, and I have no idea why it is.
I have an extension for UITextView which centers the text on a UITextView vertically that I found in the following SO answer: https://stackoverflow.com/a/38855122/4660602
My UITextView lives within a UITableViewCell, and the problem is that the function doesn't seem to work on the initial load. It only works when I reload the tableView or when I scroll.
I am calling the method within cellForRowAtIndexPath but I have tried adding it to my custom cell class in awakeFromNib and prepareForReuse but have and no luck. Wondering if anyone has any other advice / solutions.
EDIT:
Also forgot to mention, my VC with the tableView is embedded in a navigationBar and tabBar. When I switch to a new VC in the tabBar and then back, the UITextView text realigns to the top incorrectly, even if it was centered already.
Thanks!
The correct place for sizing code in a view is UIView.layoutSubviews. Since your centering function depends on the bounds, you have to call it in layoutSubviews, otherwise the bounds may not be correct (ie they match whats in the nib and not the current device). You can call setNeedsLayout in your cellforRowAtIndexPath to tell the view to update its layout after you ahve set the text.
In iOS 10, a bound of view hasn't initialized in viewDidLoad or awakeFromNib as before, so functions based on the view's bound don't work in viewDidLoad or awakeFromNib.
You should use it in viewDidAppear or when view's bound has certainly been initialized.
Works for me (Swift 5):
class VerticallyCenteredTextView: UITextView {
override var contentSize: CGSize {
didSet {
var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
topCorrection = max(0, topCorrection)
contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
}
}
}
The source - https://geek-is-stupid.github.io/2017-05-15-how-to-center-text-vertically-in-a-uitextview/
I am currently working on an iPhone App. I now have a problem with the top spacing inset of a UITableView. See this screenshot:
There should be no space between the table view cells and the buttons.
I do not know how to fix this. The UITableView is embedded in a ContainerView like this:
I think I got the container view constraints right. Top Space to Chapter Button is set to 0.
I tried to change some settings of the table view controller in storyboard. For example the Adjust Scroll View Insets. However it does not change anything when I disable that.
I also tried to set the TableView insets directly in the code in viewDidLoad():
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
However this also did not fix it.
Can anyone help? I have no idea where to look.
This can be solved by disabling auto adjustment of scroll view insets. However this setting has to be applied to the ViewController which contains the ContainerView (with the UITableView inside of it). It does not work when applied to the UITableView itself.
This can be done via Storyboard:
Or via code in viewDidLoad(): self.automaticallyAdjustsScrollViewInsets = false
Since iOS 15 there's a new parameter which can introduce a top gap when using a section header. This can be removed with the following:
if #available(iOS 15, *) {
tableView.sectionHeaderTopPadding = 0
}
Try this Hope this work.
hide View which contains the ContainerView.
self.automaticallyAdjustsScrollViewInsets = NO
I have this arrangement in Interface Builder, all properties are set to zero.
However, when I run it on both device and simulator it appears like this
Where is the space above the cells come from?
So I try to set these properties for UICollectionViewFlowLayout in code like this
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.headerReferenceSize = CGSizeZero;
layout.footerReferenceSize = CGSizeZero;
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 0;
layout.itemSize = CGSizeMake(103, 119);
self.calendarView.collectionViewLayout = layout;
but I have no luck.
How can I get rid of that space?
UICollectionView is descendant of UIScrollView class which has contentInset property, setting -20 top inset fixes the problem
[self.calendarView setContentInset:UIEdgeInsetsMake(-20, 0, 0, 0)];
However, the problem comes from UIViewController's automaticallyAdjustsScrollViewInsets property.
By documentation:
Default value is YES, which allows the view controller to adjust its scroll view insets in response to the screen areas consumed by the status bar, navigation bar, and toolbar or tab bar. Set to NO if you want to manage scroll view inset adjustments yourself.
That's why we get adjusted content insets for status bar. It's better to disable automatically adjusting than manually set value which doesn't match in result picture.
[self setAutomaticallyAdjustsScrollViewInsets:NO];
Another way is to select your ViewController and uncheck the checkbox Adjust Scroll View Insets in your interface builder:
It is essentially the same as the following line of code. But you got to see your changes right away in the interface builder.
automaticallyAdjustsScrollViewInsets = false
iOS 11 deprecated the use of automaticallyAdjustsScrollViewInsets, so the use of collectionView.contentInsetAdjustmentBehavior = .never is advised.
Here is the answer in swift with a few adjustments:
I have a collection view that takes up a small portion of the view. I used:
self.automaticallyAdjustsScrollViewInsets = false
to remove the top spacing that was messing up my layout. This piece of code didn't work for me:
self.paperCollectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
And neither did this one:
self.paperCollectionView.contentInset = UIEdgeInsetsMake(-20, 0, 0, 0)
But that might be because I'm not using a UICollectionViewController, I'm just using a UICollectionView.
Here's a bigger portion of the code to give more context:
You can also go with
[self.calendarView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
[self setAutomaticallyAdjustsScrollViewInsets:NO];
There is by default collection view header scrolling space added on the collection view and you do not need to add -20 from top because it may reflect on device issue
You can do this in Interface Builder by going to the Scroll View section and changing the Content insets dropdown to "Never".
Swift 3:
self.automaticallyAdjustsScrollViewInsets = false
This answer is weird, but it works if you are working in Interface Builder and have a Collection View embedded in a View Controller that is under the control of a Tab Bar Controller that is the root view controller of a Navigation Controller.
Add a Toolbar to the View Controller that has the Collection View
Move the Toolbar in the hierarchy such that it is above the Collection View
If the Toolbar is above the Collection View, there will be no space from the top of the prototype Collection View Cell to the Collection View. If there is no Toolbar or the Toolbar is below the Collection View, then there will be space between the top of the Collection View and the Collection View Cell. This is true both in the Storyboard preview and while running the app. The same type of thing occurs for Table Views.
This was most recently tested with Xcode Version 8.3.3
I need to add some blank space to the top of my UITableView that does not affect the size of the content area. Shifting the content down or adding a blank cell is NOT what I want to do. Instead I just want an offset.
How?
I'm not sure if I'm following you but I think I'm having the same predicament. In my case I must give some space to the ADBannerView at the top of the screen so what I did was in the viewDidLoad method I added:
[self.tableView setContentInset:UIEdgeInsetsMake(50,0,0,0)];
the values it takes are UIEdgeInsetsMake(top,left,bottom,right).
Alternatively the same with Swift:
self.tableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
Swift 4.2:
self.tableView.contentInset = UIEdgeInsets(top: 50, left: 0, bottom: 0, right: 0)
Swift 5.1
add the following in viewDidLoad
tableView.contentInset.top = 100
Really that's all there is to it.
override func viewDidLoad() {
super.viewDidLoad()
tableView.contentInset.top = 100
}
You can add an "empty" header view to the table... this would give the initial appearance of the table to have an offset, but once you started scrolling the offset would be gone. NOt sure that's what you want.
If you need a permanent offset and are not already using section headers, then you could create the offset similarly to above by making custom views for the section headers, especially if you just have one section, this could give you the look of a permanent offset.
I can post sample code if it sounds like either of those are what you are looking for.
I combined Jigzat's answer with:
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 320, 1) animated:NO];
in
- (void)viewDidLoad
so the first cell isn't at the top.
Sounds like you want to wrap a 'View' around your UITableView. If you have a UITableViewController in IB the UITableView will automatically be set to the view of UITableViewController. You change view property to a normal UIView and add your UITableView in there and give it a offset.
---Edit---
I just read my post and thought it made little sense :) When you create a UITableViewController you get this (in pseudo code):
UITableViewController.view = UITableView
This means that the actual table will take up the whole space and you cannot even add other views. So you need to change the
UITableViewController.view = UIView
and add your table to that UIView
I combined this answer with this one:
https://stackoverflow.com/a/9450345/1993937
To make the tableView appear at the top of the content inset, so the space at the top isn't cut off by having the tableView scrolled down slightly when the view initially appears. (18 is my top gap)
[self.tableView setContentInset:UIEdgeInsetsMake(18,0,0,0)];
[self.tableView setContentOffset:
CGPointMake(0, -self.songListTable.contentInset.top) animated:YES];