UICollectionView not scrolling when stat scrolling from UICollectionViewCell - swift

I'm trying to create dynamic UICollectionView for my application using code below, the problem is that when i start scrolling from CollectionViewCell it's not scrolling but when i start scroll from outside it works fine.
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.minimumInteritemSpacing = 10
flowLayout.minimumLineSpacing = 10
let collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: flowLayout)
registerCell(collectionView: collectionView)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
_scrollView.addSubview(collectionView)
You can Watch video
CollectionViewCell's properties

Make sure the cells don't have a custom touch-down event (e.g. tap gesture recognizer, or touchesBegan method without calling the super inside) and also make sure the collection view delays content touches, it's a common mistake to uncheck it and forget it.

Related

White Space at the bottom of a tableview

I have a viewcontroller with a tableview inside it. At the bottom of the tableview there is some white space that I want to get rid of and be replaced by my background colour.
I have added and customised the tableview programatically so I am looking for a programatic answer, as I did not use storyboard much for this. (I had only used it to setup my TabBarController and link it to navigation and view-controllers.)
Below is the some of the code I used to configure the tableview.
private let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.register(ProfileTableViewCell.self, forCellReuseIdentifier: ProfileTableViewCell.identifier)
tableView.backgroundColor = Constants.backgroundColor
return tableView
}()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}
Im sure the answer is probably just a single line of code, but I couldn't find one that worked. Thanks in advance!
***EDIT
I have found a solution, but I still think there is a better way to solve this problem. The code below sets a UIView as the background of the tableview, then changes the colour of the UIView.
private let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.register(ProfileTableViewCell.self, forCellReuseIdentifier: ProfileTableViewCell.identifier)
let backgroundView = UIView(frame: CGRect(x: 0,
y: 0,
width: tableView.bounds.size.width,
height: tableView.bounds.size.height))
backgroundView.backgroundColor = Constants.backgroundColor
tableView.backgroundView = backgroundView
return tableView
}()
The default color of the containing view controller is showing, since the table is short. Try setting the view controller's view's background color in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad();
view.backgroundColor = Constants.backgroundColor
}

UISearchController blocks UICollectionViewCell tap

I have a view controller with only one element inside - UICollectionView. This UIViewController is embedded in UINavigationController. In viewDidLoad method of this ViewController, I am initialising UISearchController and adding it to NavigationController. The problem is that whenever I try to search for something and I am currently entering the text in search bar, I need to tap 2 times on the UICollectionViewCell in order to trigger the tap. It looks like UISearchController is blocking the tap gesture of UICollectionViewCell. When I tap for the first time, the only thing that is happening is that "Cancel" button of the search bar is hiding. And then I need to tap another time to actually trigger the tap. I have tried many things to fix that, because I don't want the user having to tap 2 times on the cell instead of 1. These are the methods that I am calling in viewDidLoad method of this ViewController:
UISearchController initialisation:
searchController.searchResultsUpdater = self
navigationItem.hidesSearchBarWhenScrolling = false
navigationItem.searchController = searchController
definesPresentationContext = true
UICollectionView initialisation:
self.collectionView?.delegate = self
self.collectionView?.register(MyCell.self, forCellWithReuseIdentifier: MyCell.identifier)
self.collectionView?.contentInset = UIEdgeInsets(top: collectionViewVerticalInset, left: collectionViewHorizontalInset, bottom: collectionViewVerticalInset, right: collectionViewHorizontalInset)
UICollectionView layout initialisation:
let layout = UICollectionViewFlowLayout()
self.collectionView?.collectionViewLayout = layout
guard let collectionView = collectionView else { return }
UICollectionView data source initialisation:
dataSource = UICollectionViewDiffableDataSource<Section, MyEntity>(collectionView: collectionView) { (collectionView, indexPath, myEntity) -> UICollectionViewCell in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCell, for: indexPath) as! MyCell
cell.setupCell(myEntity: MyEntity)
return cell
}
I didn't changed anything in UICollectionView inside the storyboard. Also this ViewController is presented modally.

UICollectionView not scrolling after custom UIView added to view

I'm trying to add a custom UIView after adding a UICollectionView because I wanna show the custom bar view above the collection view. This is my code:
func loadFilters() {
let categoriesFlowLayout = UICollectionViewFlowLayout()
categoriesFlowLayout.scrollDirection = .vertical
categoriesCollection = UICollectionView(frame: CGRect(x: 10, y: getY(yAxis: searchField) + 10, width: view.frame.size.width - 20, height: (view.frame.size.height * 9 / 10) - getY(yAxis: searchField) - 10), collectionViewLayout: categoriesFlowLayout)
categoriesCollection.register(categoriesCell.self, forCellWithReuseIdentifier: "categoriesCell")
categoriesCollection.delegate = self
categoriesCollection.dataSource = self
categoriesCollection.backgroundColor = UIColor.clear
categoriesCollection.showsVerticalScrollIndicator = false
categoriesCollection.showsHorizontalScrollIndicator = false
view.addSubview(categoriesCollection)
addBar()
categoriesCollection.isUserInteractionEnabled = true
}
The addBar() function is declared in the custom superclass ViewController
if addBar() is called before view.addSubview(categoriesCollection) it looks like the image below but if it is called after then my collection view does not scroll or recognize touches. Is there anyway that will make the collection view scroll and bring the custom bar to front?
I've used sendSubviewToBack() and bringSubviewToFront() functions as well but the result is the same
When you insert a view above another view, the top view gets all touch events. So the UICollectionView does not receive any touch events anymore since another view is above it.
As I see from your post, you just want the bar at the bottom of the screen. So check the size of your custom UIView. It probably fills the entire screen and is completely above the UICollectionView. Just give the UIView some sort of background color and see, how much space it fills.
If this doesn't work, you can use a UIGestureRecognizer on the custom UIView and forward the touch events to the UICollectionView.

Can't get rid of a UIviewcontroller header

I am trying to get rid of a header(extra-padding) that appears on the top of my view when I run the simulator. I have tried by setting the layout reference size to zero but is not working. The collectionview is only a small part of my screen that is why I'm not sure what it is. The header looks like that of a navigationview.
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.headerReferenceSize = CGSize.zero
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.white
cv.dataSource = self
cv.delegate = self
cv.isPagingEnabled = true
cv.showsHorizontalScrollIndicator = false
return cv
}()
With translucent navigation view controller's view content starts from top of navigation bar. If you want to layout view to start from bottom of navigation bar, set isTranslucent to false (available in interface builder).
Use proper contentInset of collection view
thanks for the help! I finally realized what it was, I'm doing my views programmatically and didn't realize that my view was a navigationController.
Here's what did it for me:
self.navigationController?.isNavigationBarHidden = true;

How to add an UICollectionViewLayout programmatically?

I'm trying to setup a UICollectionViewLayout programmatically. I'm using a UICollectionView also without using storyboards, as well as settings its constraints.
I've followed Ray Wenderlich tutorial on the subject with some changes to adapt the code to Swift 3 (as AZCoder2 did https://github.com/AZCoder2/Pinterest).
Since all these examples uses storyboards, I've also introduced some changes to create the UICollectionView and its UICollectionViewLayout:
collectionViewLayout = PinterestLayout()
collectionViewLayout.delegate = self
collectionView = UICollectionView.init(frame: .zero, collectionViewLayout: collectionViewLayout)
The result: I can't see anything. If I change the UICollectionViewLayout with the one that Apple provides (UICollectionViewFlowLayout), at least I can see the cells with their content. If I implement some changes and use the storyboard, everything works great but it's not the way I want to accomplish this. The whole view is made programmatically and the collection view is a part of it.
What am I missing? Is it something to do with the way I instantiate the UICollectionViewLayout? Do I have to register something (for example, as I need to register the reusable cell)?
How about you just create a variable that creates your flow layout for you like this
var flowLayout: UICollectionViewFlowLayout {
let _flowLayout = UICollectionViewFlowLayout()
// edit properties here
_flowLayout.itemSize = CGSize(width: 98, height: 134)
_flowLayout.sectionInset = UIEdgeInsetsMake(0, 5, 0, 5)
_flowLayout.scrollDirection = UICollectionViewScrollDirection.horizontal
_flowLayout.minimumInteritemSpacing = 0.0
// edit properties here
return _flowLayout
}
And then you can set it by calling the variable.
self.collectionView.collectionViewLayout = flowLayout // after initializing it another way
// or
UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
I think this will work.
override init(collectionViewLayout layout: UICollectionViewLayout) {
super.init(collectionViewLayout: layout)
collectionView?.collectionViewLayout = YourCollectionViewLayout()
}
It's possible to do what I was trying to do. Basically, follow the tutorials I suggested in my own question and setup the collection view and its view layout as follow:
collectionViewLayout = PinterestLayout()
collectionViewLayout.delegate = self
collectionView = DynamicCollectionView.init(frame: .zero, collectionViewLayout: collectionViewLayout)
Note that I'm using DynamicCollectionView (instead of UICollectionView). This class is not provided by Apple: I've made my own using the code provided in this post.
Remember that this approach is when you're creating a view programmatically, using constraints. (May be it has another cases of use)
I resolved this issue taking these steps:
1 - Changing UICollectionViewController to a UIViewController with a collectionView inside.
2 - On ViewDidLoad I set the delegates and add the view, as usual. Moreover, I instantiate the ViewLayout and use it to instantiate the CollectionView
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.isToolbarHidden = true
let layout = MosaicViewLayout()
layout.delegate = self
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
guard let collectionView = collectionView else {
return
}
view.addSubview(collectionView)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(PhotoCell.self, forCellWithReuseIdentifier: "CharacterCell")
setupCollectionConstraints()
}
3 - On the ViewLayout the protocol stays like this:
protocol MosaicViewLayoutDelegate:class {
func collectionView(_ collectionView: UICollectionView,
heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat
}
Don't forget to add the instance inside the class
weak var delegate: MosaicViewLayoutDelegate?
4 - Add the delegate extension to you ViewController
extension HomeViewImpl: MosaicViewLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat {
let random = arc4random_uniform(4) + 1
return CGFloat(random * 100)
}
}
enter code here