Swift iOS how to remove top padding UICollectionView - ios

override func viewDidLoad(){
super.viewDidLoad()
scrollView.collectionViewLayout = layout
scrollView.delegate = self
scrollView.dataSource = self
scrollView.contentInset = .zero
scrollView.scrollIndicatorInsets = .zero
scrollView.isDirectionalLockEnabled = true
scrollView.register(UINib(nibName: "RadioView", bundle: nil), forCellWithReuseIdentifier: "RadioViewController")
}
lazy var layout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.headerReferenceSize = .zero
layout.sectionInset = .zero
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
return layout
}()
background Color Red is UICollectionView
backgorund Color Black is UICollectionViewCell
i want move Cell to left top

If it's not a Layout constraint problem, than:
collectionView.contentInset = UIEdgeInsets.zero
It is also possible that you have implemented:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
//...
}
In that case you need to set the methods return value top property to 0

Try setting these two property of UIViewController in viewDidLoad
extendedLayoutIncludesOpaqueBars = true
automaticallyAdjustsScrollViewInsets = false
Please check the header size in the storyboard, try setting them to zero.

I think this is the problem set the value of Y component to zero

Related

UICollectionViewCell changes height when keyboard appears swift 4.2

I have been working on an app that has a UICollectionView that works like the main screen with the UICollectionViewCells acting as different pages (scrolling horizontally). I have added a text field on each cell to edit, but when I click on the textfield, the cell height is extended when the keyboard appears. When the keyboard is hidden the cell height remains extended. I have been searching for an answer to this problem, but I have not come across a solution that works.
I have tried to invalidate the layout, set the translatesAutoresizingMaskIntoConstraints to false, and directly setting the content offset to zero. None of these options have fixed the issue.
Below is my code:
private let reuseIdentifier = ["Cell1", "Cell2", "Cell3", "Cell4", "Cell5"]
let navi_btn_array: [UIButton] = [navi_home_btn, navi_gavel_btn, navi_orders_btn, navi_profile_btn, navi_lightning_btn]
var collectionView: UICollectionView = {
var layout = UICollectionViewFlowLayout();
layout.sectionInset = UIEdgeInsets.zero
var cv = UICollectionView(frame: .zero, collectionViewLayout: layout);
cv.autoresizesSubviews = false
cv.contentInset = UIEdgeInsets.zero
cv.translatesAutoresizingMaskIntoConstraints = false;
return cv;
}();
class MainCVC: UICollectionViewController,UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.register(SimpleDispensaryPage_Cell.self, forCellWithReuseIdentifier: reuseIdentifier[0])
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.isPagingEnabled = true
let nc:NotificationCenter = NotificationCenter.default
nc.addObserver(self, selector: #selector(keyboardDidShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
nc.addObserver(self, selector: #selector(keyboardDidHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
#objc func keyboardDidShow(notification: Notification){
collectionViewLayout.invalidateLayout()
collectionView?.contentOffset.y = 0
}
#objc func keyboardDidHide(notification: Notification){
collectionViewLayout.invalidateLayout()
collectionView?.contentOffset.y = 0
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier[0], for: indexPath)
cell.backgroundColor = Custom_Colors.color_pine.withAlphaComponent(0.5)
var txt_fld = UITextField()
txt_fld.frame = CGRect(x: 0, y: 50, width: 100, height: 50)
cell_label.text = "Placeholder #"+String(indexPath.item)
cell_label.textAlignment = .center
cell.addSubview(cell_label)
return cell
}
}
}
I also get this error when it runs:
2019-03-14 11:41:20.770799-0700 app[57379:5390785] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
2019-03-14 11:41:20.771043-0700 app[57379:5390785] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x7fda15c13f40>, and it is attached to <UICollectionView: 0x7fda1706f000; frame = (0 0; 375 730.8); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000447bc0>; layer = <CALayer: 0x600000437720>; contentOffset: {8, -38.333333333333336}; contentSize: {1891, 579}; adjustedContentInset: {0, 0, 151.79999999999995, 0}> collection view layout: <UICollectionViewFlowLayout: 0x7fda15c13f40>.
2019-03-14 11:41:20.771245-0700 app[57379:5390785] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
You have a little bit of strange setup here. I suggest making a couple of changes:
1 - Never add subviews in collectionView(_, cellForItemAt ...). This would result in multiple additions every time the cell is being reused. The subviews should be added by the cell (and preferably at creation time).
2 - Remove cv.autoresizesSubviews = false and cv.translatesAutoresizingMaskIntoConstraints = false.
3 - If you want a fixed size for your cells you can set the layout.delegate = self and implement the following method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: screenWidth, height: screenHeight)
}
4 - If you really just want a couple of pages why don't you use UIPageViewController?

One way paging in scrollview

Is there a way to allow paging in a UIScrollView but restrict the paging to one direction.
For example: Allowing the user to page background (to the left) but not forward. Use case being for some type of onboarding. I know I can add buttons that move forward, have them enabled or disabled, and remove swiping but I rather not.
I don't know if I have well understand what you want but what about using a UICollectionView:
lazy var onBoardingCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
let cv = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
cv.showsHorizontalScrollIndicator = false
cv.showsVerticalScrollIndicator = false
cv.isPagingEnabled = true
return cv
}()
You add you custom cell with the size of the screen as well by the method in UICollectionViewDelegateFlowLayout:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: SCREENW, height: SCREENH)
}
if you don't want to go in a specific direction you can try get the current cell displaying and removing the previous one of the dataSource and collection with this method.
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let currentPage = Int(scrollView.contentOffset.x / scrollView.frame.width)
print("current cell: ", currentPage)
}

UICollectionView size is wrong in sizeForItemAt on first load - after rotating it works

I have a collectionView setup as following, but in sizeForItemAt the collectionView!.frame.size is not the same as the rendered result.
Note: I am only using Constraints for the layout of the collectionView.
Any idea?
public override init(frame: CGRect){
super.init(frame: frame)
self.translatesAutoresizingMaskIntoConstraints = false
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.scrollDirection = .vertical
self.collectionView = UICollectionView(frame: self.frame, collectionViewLayout: layout)
self.addSubview(self.collectionView!)
self.collectionView?.translatesAutoresizingMaskIntoConstraints = false
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellIdentifier")
}
public func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
collectionView!.frame.size // Tot the size of the rendered collectionView, and therefore unable to give the cell the right size???
}
This is happening because the cell in your UICollectionView are loaded before the layout of the view controller is finished.
When using constraints and collection views, I noticed that it is unreliable to use the collection view size before the viewDidAppear(:) call.
If you want to do a grid layout relative to the screen size, you can use UIScreen.main.bounds.size in the sizeForItemAt method.
Here, your collection view seems to be a subview of a UIView subclass. So if you can't or don't want to use the screen size, you can also reload the collection view after its superview bounds changed:
override var bounds: CGRect {
didSet {
if oldValue != bounds {
self.collectionView?.reloadData()
}
}
}

How to remove the gap between header and cell of UICollectionView?

I have a UICollectionView and it has a header and a cell.
I want to remove the gap between the header and the cell..
How to do that in swift?
Here is my view...
I added background colour to the collectionView and header and cell also..
Please see the screenshot.
Use the property section Inset of UICollectionViewFlowLayout
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 10)
// Here you can set according your requirement
For more reference: http://www.brianjcoleman.com/tutorial-collection-view-using-swift/
use the property sectionInset of UICollectionViewFlowLayout:
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 1;
in Swift:
var layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 1
Attaching screenshot of storyboard screen. Set as per that your storyboard and check. Hope your problem will be solved.
I Forgot to set section Inset to zero.
It solved my problem.
Thanks everyone.
try this:
override func viewWillAppear(animated: Bool) {
self.automaticallyAdjustsScrollViewInsets = false;
}
On UICollectionViewDelegate:
let k_cViewPadding = 8.0
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let cellDiffference:CGFloat = CGFloat(k_cViewPadding*4)
return(CGSizeMake((collectionView.frame.size.width-cellDiffference)/3, (collectionView.frame.size.width-cellDiffference)/3))
}
Here is my sample code you have to set UIEdgeInsets for spacing.
private let collectionViewLayout: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionView.ScrollDirection.horizontal
layout.sectionInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
collectionView.register(TopExpertCustomCell.self, forCellWithReuseIdentifier: "TopExpertCollectionViewCell")
collectionView.backgroundColor = UIColor(hex: "#F1F1F1")
return collectionView
}()
Custom your UIEdgeInsetsMake:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0,0,0,0); //{top, left, bottom, right};
}

UICollectionView as UITableView subview flow layout loop

I have an UITableView and I want to add a UICollectionView with a horizontal flow layout as subview in the backgroundView of the tableView, to do the same effect of the AppStore. Here I have the implementation code:
in the viewDidLoad:
UIView *tableViewBackgroundView = [[UIView alloc] initWithFrame:self.view.bounds];
self.tableView.backgroundView = tableViewBackgroundView;
// HighlightView heightFactor returns the reason which is 9.0/16.0
CGFloat headerViewHeight = CGRectGetWidth(self.view.frame) * [HighlightView heightFactor];
self.tableView.contentInset = UIEdgeInsetsMake(headerViewHeight, 0, 0, 0);
self.headerView = [[HighlightView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), headerViewHeight)];
[tableViewBackgroundView addSubview:self.headerView];
The HighlightView is a view with a collectionView inside.
But I'm having an issue, when the user interacts with the collectionView I start to receive this log:
Please check the values return by the delegate. the behavior of the
UICollectionViewFlowLayout is not defined because: the item height
must be less than the height of the UICollectionView minus the section
insets top and bottom values.
And this becomes a loop that doesn't stop even when the user stops to interact.
HighlightView (CollectionView) code:
override init(frame: CGRect) {
super.init(frame: frame)
self.viewModel.delegate = self
self.configureHighlightsCollectionView()
}
func configureHighlightsCollectionView() {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
flowLayout.minimumInteritemSpacing = 0
flowLayout.minimumLineSpacing = 0
if systemVersion > 8.0 {
flowLayout.estimatedItemSize = self.frame.size
}
flowLayout.itemSize = self.frame.size
self.highlightsCollectionView = UICollectionView(frame: self.bounds, collectionViewLayout: flowLayout)
self.highlightsCollectionView.frame = self.bounds
self.highlightsCollectionView.scrollsToTop = false
self.highlightsCollectionView.pagingEnabled = true
self.highlightsCollectionView.registerClass(CachedImageCollectionViewCell.self, forCellWithReuseIdentifier: "ImageCell")
self.addSubview(self.highlightsCollectionView)
self.highlightsCollectionView.invalidateIntrinsicContentSize()
self.highlightsCollectionView.dataSource = self
self.highlightsCollectionView.delegate = self
self.highlightsCollectionView.backgroundColor = UIColor.greenColor()
self.highlightsCollectionView.snp_makeConstraints { (make) -> Void in
make.top.equalTo(self)
make.bottom.equalTo(self)
make.left.equalTo(self)
make.right.equalTo(self)
}
}
//Mark: UICollectionViewDataSource
public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.viewModel.highlightsArray.count
}
public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageCell", forIndexPath: indexPath) as! CachedImageCollectionViewCell
cell.highlightData = self.viewModel.highlightsArray[indexPath.item]
return cell
}
public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
println(self.frame.size)
return self.frame.size
}
The viewModel is a class who controls the data flow of the collectionView.
First I don't think it's a good idea to put your view as datasource and delegate of your UICollection inside your UIView subclass. You're not respecting the MVC pattern. Learn more informations about it at Introducing iOS Design Pattern . You should set your controller as it.
The problem is you're setting the itemSize of your UICollectionViewFlowLayout in initFrame: based on the frame of your view. In that method, the frame of your UIView is not correct since you're using AutoLayout. You have to wait until AutoLayout calculates the layouts of your views so when layoutSubviews: is called. Learn about UIView and AutoLayout in the Matt's book. It's for iOS 6 and in Objective - C but still great.

Resources