implementing UIScrollViewDelegate in a UICollectionView subclass











up vote
1
down vote

favorite












I have a UICollectionView subclass.



I want to add a default implementation for scrollViewDidScroll from UIScrollViewDelegate



Is there a way to access the scrollView delegate methods from the UICollectionView subclass?



Thanks










share|improve this question






















  • I would also like to know
    – RX9
    Nov 11 at 0:32















up vote
1
down vote

favorite












I have a UICollectionView subclass.



I want to add a default implementation for scrollViewDidScroll from UIScrollViewDelegate



Is there a way to access the scrollView delegate methods from the UICollectionView subclass?



Thanks










share|improve this question






















  • I would also like to know
    – RX9
    Nov 11 at 0:32













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I have a UICollectionView subclass.



I want to add a default implementation for scrollViewDidScroll from UIScrollViewDelegate



Is there a way to access the scrollView delegate methods from the UICollectionView subclass?



Thanks










share|improve this question













I have a UICollectionView subclass.



I want to add a default implementation for scrollViewDidScroll from UIScrollViewDelegate



Is there a way to access the scrollView delegate methods from the UICollectionView subclass?



Thanks







ios swift uiscrollview uicollectionview






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 10 at 23:22









ilan

1,75422151




1,75422151












  • I would also like to know
    – RX9
    Nov 11 at 0:32


















  • I would also like to know
    – RX9
    Nov 11 at 0:32
















I would also like to know
– RX9
Nov 11 at 0:32




I would also like to know
– RX9
Nov 11 at 0:32












2 Answers
2






active

oldest

votes

















up vote
1
down vote



accepted










You can add a function that implement the default code you need, for example:



class YourCollectionView: UICollectionView {

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateUIOnScrollViewDidScroll(_ scrollView: UIScrollView) {
//...
}
}


Then when you implement the delegate functions in your view controller, add:



func scrollViewDidScroll(_ scrollView: UIScrollView) {
yourCollectionView.updateUIOnScrollViewDidScroll(scrollView)
}


EDIT



If you want to use your collection like an external library and you don’t want to call the updated function every time, you can implement a custom class that only conform to the UICollectionViewDelegate (if you want you can have a separated CustomDataSource class too that implement data source and delegate), for example:



class YourCollectionViewDelegate: NSObject, UICollectionViewDelegate {
// implement a callback for every function you need to manage in the view controller
var onSelectedItemAt: ((IndexPath) -> Void)?
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
onSelectedItemAt?(indexPath)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? YourCollectionViewClass else { fatalError(“your message”) }
// implement your ui update
}


Then in your view controller you just have to bind the delegate with your view controller:



class MyViewController: UIViewController {

//...
let customDelegate = YourCollectionViewDelegate()

override func viewDidLoad() {
super.viewDidLoad()
//...
myCollection.delegate = customDelegate
setupBindings()
}

private func setupBindings() {

customDelegate.onSelectedItemAt = { [weak self] indexPath in
//...
}
}





share|improve this answer























  • Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
    – ilan
    Nov 11 at 0:29












  • dont want to call the the update function in every viewcontroller that has this collectionview
    – ilan
    Nov 11 at 0:30










  • I edited my answer ;) let me know if this can work for you.
    – Francesco Deliro
    Nov 11 at 10:24


















up vote
0
down vote













We can use delegation concept to get access from CustomCollectionView whenever user scrolls it.



This is the implementation of CustomCollectionView also note that the delegate method is optional which are available in Objective C.



So that, if your ViewController confirms to the CustomCollectionViewDelegate protocol then it needs to implement the delegate methods else it have not to.



Note:



However, CustomCollectionView is a subclass of UICollectionView means its simple generic UI element. In fact, it is a View in Model-View-Controller (MVC). As per MVC, View can not be directly talk to the Controller, the communication between View and Controller is blind & structured. The good examples of such kind of communication are Target & Action and delegate pattern.



The delegate is a simple variable which is contained by the generic UI components like UIScrollView, UITableView, UICollectionView, etc. The Controller has to confirms the protocol by setting up the delegate of the UI element to self to implement the delegate methods inside it.



The conclusion is the subclass of generic UI element can't implement the delegate methods inside it.



However, we can achieve that by making a customized UIView with XIB and add the collectionView to it.



Code:



CustomCollectionView:



import UIKit

@objc protocol CustomCollectionViewDelegate {

@objc optional func collectionViewDidScroll(_ scrollView: UIScrollView)
}

class CustomCollectionView: UIView {

//MARK: - Outlets
@IBOutlet weak var collection: UICollectionView!

//MARK: - Variables
weak var vc: UIViewController!
weak var view: UIView!
weak var customDelegate: CustomCollectionViewDelegate?

let titles = ["HorizontalCollectionView", "VerticalCollectionView"]

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

init(frame: CGRect, in vc: UIViewController, setCustomDelegate set: Bool) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
self.vc = vc
self.customDelegate = set ? vc as? CustomCollectionViewDelegate : nil
}

override init(frame: CGRect) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
}

private func xibSetup(frame: CGRect) {

view = loadViewFromNib()
view.frame = frame
addSubview(view)

collection.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CustomCollectionViewCell")
collection.delegate = self
collection.dataSource = self
}

private func loadViewFromNib() -> UIView {

let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomCollectionView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

return view
}

}

extension CustomCollectionView: UIScrollViewDelegate {

func scrollViewDidScroll(_ scrollView: UIScrollView) {

if customDelegate != nil {
customDelegate!.collectionViewDidScroll!(scrollView)
}
}
}

extension CustomCollectionView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return titles.count
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {

return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

return 10 // Adjust the inter item space based on the requirement.
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: 300, height: collectionView.bounds.height)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
cell.titleLabel.text = titles[indexPath.row]
return cell
}
}


CustomCollectionView XIB:



<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<connections>
<outlet property="collection" destination="loF-CI-n5C" id="EZi-It-39z"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="loF-CI-n5C">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="HQB-uW-7CY">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="loF-CI-n5C" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Khs-Aw-6b7"/>
<constraint firstItem="loF-CI-n5C" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="cEr-al-Pib"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="loF-CI-n5C" secondAttribute="bottom" id="ftp-QG-OGJ"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="loF-CI-n5C" secondAttribute="trailing" id="num-9n-spN"/>
</constraints>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="138.40000000000001" y="153.37331334332833"/>
</view>
</objects>
</document>


ViewController:



override func viewDidLoad() {
super.viewDidLoad()

let collectionView = CustomCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200), in: self, setCustomDelegate: true)
view.addSubview(collectionView)
}


Delegate Implementation:



extension ViewController: CustomCollectionViewDelegate {

func collectionViewDidScroll(_ scrollView: UIScrollView) {

//do something...
}
}





share|improve this answer























  • You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
    – ilan
    Nov 11 at 9:07










  • Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
    – Sateesh
    Nov 11 at 13:20











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244392%2fimplementing-uiscrollviewdelegate-in-a-uicollectionview-subclass%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



accepted










You can add a function that implement the default code you need, for example:



class YourCollectionView: UICollectionView {

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateUIOnScrollViewDidScroll(_ scrollView: UIScrollView) {
//...
}
}


Then when you implement the delegate functions in your view controller, add:



func scrollViewDidScroll(_ scrollView: UIScrollView) {
yourCollectionView.updateUIOnScrollViewDidScroll(scrollView)
}


EDIT



If you want to use your collection like an external library and you don’t want to call the updated function every time, you can implement a custom class that only conform to the UICollectionViewDelegate (if you want you can have a separated CustomDataSource class too that implement data source and delegate), for example:



class YourCollectionViewDelegate: NSObject, UICollectionViewDelegate {
// implement a callback for every function you need to manage in the view controller
var onSelectedItemAt: ((IndexPath) -> Void)?
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
onSelectedItemAt?(indexPath)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? YourCollectionViewClass else { fatalError(“your message”) }
// implement your ui update
}


Then in your view controller you just have to bind the delegate with your view controller:



class MyViewController: UIViewController {

//...
let customDelegate = YourCollectionViewDelegate()

override func viewDidLoad() {
super.viewDidLoad()
//...
myCollection.delegate = customDelegate
setupBindings()
}

private func setupBindings() {

customDelegate.onSelectedItemAt = { [weak self] indexPath in
//...
}
}





share|improve this answer























  • Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
    – ilan
    Nov 11 at 0:29












  • dont want to call the the update function in every viewcontroller that has this collectionview
    – ilan
    Nov 11 at 0:30










  • I edited my answer ;) let me know if this can work for you.
    – Francesco Deliro
    Nov 11 at 10:24















up vote
1
down vote



accepted










You can add a function that implement the default code you need, for example:



class YourCollectionView: UICollectionView {

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateUIOnScrollViewDidScroll(_ scrollView: UIScrollView) {
//...
}
}


Then when you implement the delegate functions in your view controller, add:



func scrollViewDidScroll(_ scrollView: UIScrollView) {
yourCollectionView.updateUIOnScrollViewDidScroll(scrollView)
}


EDIT



If you want to use your collection like an external library and you don’t want to call the updated function every time, you can implement a custom class that only conform to the UICollectionViewDelegate (if you want you can have a separated CustomDataSource class too that implement data source and delegate), for example:



class YourCollectionViewDelegate: NSObject, UICollectionViewDelegate {
// implement a callback for every function you need to manage in the view controller
var onSelectedItemAt: ((IndexPath) -> Void)?
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
onSelectedItemAt?(indexPath)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? YourCollectionViewClass else { fatalError(“your message”) }
// implement your ui update
}


Then in your view controller you just have to bind the delegate with your view controller:



class MyViewController: UIViewController {

//...
let customDelegate = YourCollectionViewDelegate()

override func viewDidLoad() {
super.viewDidLoad()
//...
myCollection.delegate = customDelegate
setupBindings()
}

private func setupBindings() {

customDelegate.onSelectedItemAt = { [weak self] indexPath in
//...
}
}





share|improve this answer























  • Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
    – ilan
    Nov 11 at 0:29












  • dont want to call the the update function in every viewcontroller that has this collectionview
    – ilan
    Nov 11 at 0:30










  • I edited my answer ;) let me know if this can work for you.
    – Francesco Deliro
    Nov 11 at 10:24













up vote
1
down vote



accepted







up vote
1
down vote



accepted






You can add a function that implement the default code you need, for example:



class YourCollectionView: UICollectionView {

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateUIOnScrollViewDidScroll(_ scrollView: UIScrollView) {
//...
}
}


Then when you implement the delegate functions in your view controller, add:



func scrollViewDidScroll(_ scrollView: UIScrollView) {
yourCollectionView.updateUIOnScrollViewDidScroll(scrollView)
}


EDIT



If you want to use your collection like an external library and you don’t want to call the updated function every time, you can implement a custom class that only conform to the UICollectionViewDelegate (if you want you can have a separated CustomDataSource class too that implement data source and delegate), for example:



class YourCollectionViewDelegate: NSObject, UICollectionViewDelegate {
// implement a callback for every function you need to manage in the view controller
var onSelectedItemAt: ((IndexPath) -> Void)?
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
onSelectedItemAt?(indexPath)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? YourCollectionViewClass else { fatalError(“your message”) }
// implement your ui update
}


Then in your view controller you just have to bind the delegate with your view controller:



class MyViewController: UIViewController {

//...
let customDelegate = YourCollectionViewDelegate()

override func viewDidLoad() {
super.viewDidLoad()
//...
myCollection.delegate = customDelegate
setupBindings()
}

private func setupBindings() {

customDelegate.onSelectedItemAt = { [weak self] indexPath in
//...
}
}





share|improve this answer














You can add a function that implement the default code you need, for example:



class YourCollectionView: UICollectionView {

override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func updateUIOnScrollViewDidScroll(_ scrollView: UIScrollView) {
//...
}
}


Then when you implement the delegate functions in your view controller, add:



func scrollViewDidScroll(_ scrollView: UIScrollView) {
yourCollectionView.updateUIOnScrollViewDidScroll(scrollView)
}


EDIT



If you want to use your collection like an external library and you don’t want to call the updated function every time, you can implement a custom class that only conform to the UICollectionViewDelegate (if you want you can have a separated CustomDataSource class too that implement data source and delegate), for example:



class YourCollectionViewDelegate: NSObject, UICollectionViewDelegate {
// implement a callback for every function you need to manage in the view controller
var onSelectedItemAt: ((IndexPath) -> Void)?
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
onSelectedItemAt?(indexPath)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let collectionView = scrollView as? YourCollectionViewClass else { fatalError(“your message”) }
// implement your ui update
}


Then in your view controller you just have to bind the delegate with your view controller:



class MyViewController: UIViewController {

//...
let customDelegate = YourCollectionViewDelegate()

override func viewDidLoad() {
super.viewDidLoad()
//...
myCollection.delegate = customDelegate
setupBindings()
}

private func setupBindings() {

customDelegate.onSelectedItemAt = { [weak self] indexPath in
//...
}
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 11 at 12:29

























answered Nov 11 at 0:15









Francesco Deliro

2,3992716




2,3992716












  • Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
    – ilan
    Nov 11 at 0:29












  • dont want to call the the update function in every viewcontroller that has this collectionview
    – ilan
    Nov 11 at 0:30










  • I edited my answer ;) let me know if this can work for you.
    – Francesco Deliro
    Nov 11 at 10:24


















  • Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
    – ilan
    Nov 11 at 0:29












  • dont want to call the the update function in every viewcontroller that has this collectionview
    – ilan
    Nov 11 at 0:30










  • I edited my answer ;) let me know if this can work for you.
    – Francesco Deliro
    Nov 11 at 10:24
















Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
– ilan
Nov 11 at 0:29






Thanks, i have a CollectionView with some functionality that is the same across all the app. I want this to work like an external library.
– ilan
Nov 11 at 0:29














dont want to call the the update function in every viewcontroller that has this collectionview
– ilan
Nov 11 at 0:30




dont want to call the the update function in every viewcontroller that has this collectionview
– ilan
Nov 11 at 0:30












I edited my answer ;) let me know if this can work for you.
– Francesco Deliro
Nov 11 at 10:24




I edited my answer ;) let me know if this can work for you.
– Francesco Deliro
Nov 11 at 10:24












up vote
0
down vote













We can use delegation concept to get access from CustomCollectionView whenever user scrolls it.



This is the implementation of CustomCollectionView also note that the delegate method is optional which are available in Objective C.



So that, if your ViewController confirms to the CustomCollectionViewDelegate protocol then it needs to implement the delegate methods else it have not to.



Note:



However, CustomCollectionView is a subclass of UICollectionView means its simple generic UI element. In fact, it is a View in Model-View-Controller (MVC). As per MVC, View can not be directly talk to the Controller, the communication between View and Controller is blind & structured. The good examples of such kind of communication are Target & Action and delegate pattern.



The delegate is a simple variable which is contained by the generic UI components like UIScrollView, UITableView, UICollectionView, etc. The Controller has to confirms the protocol by setting up the delegate of the UI element to self to implement the delegate methods inside it.



The conclusion is the subclass of generic UI element can't implement the delegate methods inside it.



However, we can achieve that by making a customized UIView with XIB and add the collectionView to it.



Code:



CustomCollectionView:



import UIKit

@objc protocol CustomCollectionViewDelegate {

@objc optional func collectionViewDidScroll(_ scrollView: UIScrollView)
}

class CustomCollectionView: UIView {

//MARK: - Outlets
@IBOutlet weak var collection: UICollectionView!

//MARK: - Variables
weak var vc: UIViewController!
weak var view: UIView!
weak var customDelegate: CustomCollectionViewDelegate?

let titles = ["HorizontalCollectionView", "VerticalCollectionView"]

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

init(frame: CGRect, in vc: UIViewController, setCustomDelegate set: Bool) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
self.vc = vc
self.customDelegate = set ? vc as? CustomCollectionViewDelegate : nil
}

override init(frame: CGRect) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
}

private func xibSetup(frame: CGRect) {

view = loadViewFromNib()
view.frame = frame
addSubview(view)

collection.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CustomCollectionViewCell")
collection.delegate = self
collection.dataSource = self
}

private func loadViewFromNib() -> UIView {

let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomCollectionView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

return view
}

}

extension CustomCollectionView: UIScrollViewDelegate {

func scrollViewDidScroll(_ scrollView: UIScrollView) {

if customDelegate != nil {
customDelegate!.collectionViewDidScroll!(scrollView)
}
}
}

extension CustomCollectionView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return titles.count
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {

return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

return 10 // Adjust the inter item space based on the requirement.
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: 300, height: collectionView.bounds.height)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
cell.titleLabel.text = titles[indexPath.row]
return cell
}
}


CustomCollectionView XIB:



<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<connections>
<outlet property="collection" destination="loF-CI-n5C" id="EZi-It-39z"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="loF-CI-n5C">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="HQB-uW-7CY">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="loF-CI-n5C" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Khs-Aw-6b7"/>
<constraint firstItem="loF-CI-n5C" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="cEr-al-Pib"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="loF-CI-n5C" secondAttribute="bottom" id="ftp-QG-OGJ"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="loF-CI-n5C" secondAttribute="trailing" id="num-9n-spN"/>
</constraints>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="138.40000000000001" y="153.37331334332833"/>
</view>
</objects>
</document>


ViewController:



override func viewDidLoad() {
super.viewDidLoad()

let collectionView = CustomCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200), in: self, setCustomDelegate: true)
view.addSubview(collectionView)
}


Delegate Implementation:



extension ViewController: CustomCollectionViewDelegate {

func collectionViewDidScroll(_ scrollView: UIScrollView) {

//do something...
}
}





share|improve this answer























  • You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
    – ilan
    Nov 11 at 9:07










  • Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
    – Sateesh
    Nov 11 at 13:20















up vote
0
down vote













We can use delegation concept to get access from CustomCollectionView whenever user scrolls it.



This is the implementation of CustomCollectionView also note that the delegate method is optional which are available in Objective C.



So that, if your ViewController confirms to the CustomCollectionViewDelegate protocol then it needs to implement the delegate methods else it have not to.



Note:



However, CustomCollectionView is a subclass of UICollectionView means its simple generic UI element. In fact, it is a View in Model-View-Controller (MVC). As per MVC, View can not be directly talk to the Controller, the communication between View and Controller is blind & structured. The good examples of such kind of communication are Target & Action and delegate pattern.



The delegate is a simple variable which is contained by the generic UI components like UIScrollView, UITableView, UICollectionView, etc. The Controller has to confirms the protocol by setting up the delegate of the UI element to self to implement the delegate methods inside it.



The conclusion is the subclass of generic UI element can't implement the delegate methods inside it.



However, we can achieve that by making a customized UIView with XIB and add the collectionView to it.



Code:



CustomCollectionView:



import UIKit

@objc protocol CustomCollectionViewDelegate {

@objc optional func collectionViewDidScroll(_ scrollView: UIScrollView)
}

class CustomCollectionView: UIView {

//MARK: - Outlets
@IBOutlet weak var collection: UICollectionView!

//MARK: - Variables
weak var vc: UIViewController!
weak var view: UIView!
weak var customDelegate: CustomCollectionViewDelegate?

let titles = ["HorizontalCollectionView", "VerticalCollectionView"]

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

init(frame: CGRect, in vc: UIViewController, setCustomDelegate set: Bool) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
self.vc = vc
self.customDelegate = set ? vc as? CustomCollectionViewDelegate : nil
}

override init(frame: CGRect) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
}

private func xibSetup(frame: CGRect) {

view = loadViewFromNib()
view.frame = frame
addSubview(view)

collection.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CustomCollectionViewCell")
collection.delegate = self
collection.dataSource = self
}

private func loadViewFromNib() -> UIView {

let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomCollectionView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

return view
}

}

extension CustomCollectionView: UIScrollViewDelegate {

func scrollViewDidScroll(_ scrollView: UIScrollView) {

if customDelegate != nil {
customDelegate!.collectionViewDidScroll!(scrollView)
}
}
}

extension CustomCollectionView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return titles.count
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {

return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

return 10 // Adjust the inter item space based on the requirement.
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: 300, height: collectionView.bounds.height)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
cell.titleLabel.text = titles[indexPath.row]
return cell
}
}


CustomCollectionView XIB:



<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<connections>
<outlet property="collection" destination="loF-CI-n5C" id="EZi-It-39z"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="loF-CI-n5C">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="HQB-uW-7CY">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="loF-CI-n5C" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Khs-Aw-6b7"/>
<constraint firstItem="loF-CI-n5C" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="cEr-al-Pib"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="loF-CI-n5C" secondAttribute="bottom" id="ftp-QG-OGJ"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="loF-CI-n5C" secondAttribute="trailing" id="num-9n-spN"/>
</constraints>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="138.40000000000001" y="153.37331334332833"/>
</view>
</objects>
</document>


ViewController:



override func viewDidLoad() {
super.viewDidLoad()

let collectionView = CustomCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200), in: self, setCustomDelegate: true)
view.addSubview(collectionView)
}


Delegate Implementation:



extension ViewController: CustomCollectionViewDelegate {

func collectionViewDidScroll(_ scrollView: UIScrollView) {

//do something...
}
}





share|improve this answer























  • You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
    – ilan
    Nov 11 at 9:07










  • Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
    – Sateesh
    Nov 11 at 13:20













up vote
0
down vote










up vote
0
down vote









We can use delegation concept to get access from CustomCollectionView whenever user scrolls it.



This is the implementation of CustomCollectionView also note that the delegate method is optional which are available in Objective C.



So that, if your ViewController confirms to the CustomCollectionViewDelegate protocol then it needs to implement the delegate methods else it have not to.



Note:



However, CustomCollectionView is a subclass of UICollectionView means its simple generic UI element. In fact, it is a View in Model-View-Controller (MVC). As per MVC, View can not be directly talk to the Controller, the communication between View and Controller is blind & structured. The good examples of such kind of communication are Target & Action and delegate pattern.



The delegate is a simple variable which is contained by the generic UI components like UIScrollView, UITableView, UICollectionView, etc. The Controller has to confirms the protocol by setting up the delegate of the UI element to self to implement the delegate methods inside it.



The conclusion is the subclass of generic UI element can't implement the delegate methods inside it.



However, we can achieve that by making a customized UIView with XIB and add the collectionView to it.



Code:



CustomCollectionView:



import UIKit

@objc protocol CustomCollectionViewDelegate {

@objc optional func collectionViewDidScroll(_ scrollView: UIScrollView)
}

class CustomCollectionView: UIView {

//MARK: - Outlets
@IBOutlet weak var collection: UICollectionView!

//MARK: - Variables
weak var vc: UIViewController!
weak var view: UIView!
weak var customDelegate: CustomCollectionViewDelegate?

let titles = ["HorizontalCollectionView", "VerticalCollectionView"]

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

init(frame: CGRect, in vc: UIViewController, setCustomDelegate set: Bool) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
self.vc = vc
self.customDelegate = set ? vc as? CustomCollectionViewDelegate : nil
}

override init(frame: CGRect) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
}

private func xibSetup(frame: CGRect) {

view = loadViewFromNib()
view.frame = frame
addSubview(view)

collection.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CustomCollectionViewCell")
collection.delegate = self
collection.dataSource = self
}

private func loadViewFromNib() -> UIView {

let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomCollectionView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

return view
}

}

extension CustomCollectionView: UIScrollViewDelegate {

func scrollViewDidScroll(_ scrollView: UIScrollView) {

if customDelegate != nil {
customDelegate!.collectionViewDidScroll!(scrollView)
}
}
}

extension CustomCollectionView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return titles.count
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {

return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

return 10 // Adjust the inter item space based on the requirement.
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: 300, height: collectionView.bounds.height)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
cell.titleLabel.text = titles[indexPath.row]
return cell
}
}


CustomCollectionView XIB:



<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<connections>
<outlet property="collection" destination="loF-CI-n5C" id="EZi-It-39z"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="loF-CI-n5C">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="HQB-uW-7CY">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="loF-CI-n5C" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Khs-Aw-6b7"/>
<constraint firstItem="loF-CI-n5C" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="cEr-al-Pib"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="loF-CI-n5C" secondAttribute="bottom" id="ftp-QG-OGJ"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="loF-CI-n5C" secondAttribute="trailing" id="num-9n-spN"/>
</constraints>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="138.40000000000001" y="153.37331334332833"/>
</view>
</objects>
</document>


ViewController:



override func viewDidLoad() {
super.viewDidLoad()

let collectionView = CustomCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200), in: self, setCustomDelegate: true)
view.addSubview(collectionView)
}


Delegate Implementation:



extension ViewController: CustomCollectionViewDelegate {

func collectionViewDidScroll(_ scrollView: UIScrollView) {

//do something...
}
}





share|improve this answer














We can use delegation concept to get access from CustomCollectionView whenever user scrolls it.



This is the implementation of CustomCollectionView also note that the delegate method is optional which are available in Objective C.



So that, if your ViewController confirms to the CustomCollectionViewDelegate protocol then it needs to implement the delegate methods else it have not to.



Note:



However, CustomCollectionView is a subclass of UICollectionView means its simple generic UI element. In fact, it is a View in Model-View-Controller (MVC). As per MVC, View can not be directly talk to the Controller, the communication between View and Controller is blind & structured. The good examples of such kind of communication are Target & Action and delegate pattern.



The delegate is a simple variable which is contained by the generic UI components like UIScrollView, UITableView, UICollectionView, etc. The Controller has to confirms the protocol by setting up the delegate of the UI element to self to implement the delegate methods inside it.



The conclusion is the subclass of generic UI element can't implement the delegate methods inside it.



However, we can achieve that by making a customized UIView with XIB and add the collectionView to it.



Code:



CustomCollectionView:



import UIKit

@objc protocol CustomCollectionViewDelegate {

@objc optional func collectionViewDidScroll(_ scrollView: UIScrollView)
}

class CustomCollectionView: UIView {

//MARK: - Outlets
@IBOutlet weak var collection: UICollectionView!

//MARK: - Variables
weak var vc: UIViewController!
weak var view: UIView!
weak var customDelegate: CustomCollectionViewDelegate?

let titles = ["HorizontalCollectionView", "VerticalCollectionView"]

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

init(frame: CGRect, in vc: UIViewController, setCustomDelegate set: Bool) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
self.vc = vc
self.customDelegate = set ? vc as? CustomCollectionViewDelegate : nil
}

override init(frame: CGRect) {
super.init(frame: frame)
xibSetup(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height))
}

private func xibSetup(frame: CGRect) {

view = loadViewFromNib()
view.frame = frame
addSubview(view)

collection.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CustomCollectionViewCell")
collection.delegate = self
collection.dataSource = self
}

private func loadViewFromNib() -> UIView {

let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CustomCollectionView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

return view
}

}

extension CustomCollectionView: UIScrollViewDelegate {

func scrollViewDidScroll(_ scrollView: UIScrollView) {

if customDelegate != nil {
customDelegate!.collectionViewDidScroll!(scrollView)
}
}
}

extension CustomCollectionView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return titles.count
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {

return 0
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

return 10 // Adjust the inter item space based on the requirement.
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: 300, height: collectionView.bounds.height)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
cell.titleLabel.text = titles[indexPath.row]
return cell
}
}


CustomCollectionView XIB:



<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<connections>
<outlet property="collection" destination="loF-CI-n5C" id="EZi-It-39z"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CustomCollectionView" customModule="SampleDemoApp" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="loF-CI-n5C">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="HQB-uW-7CY">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="loF-CI-n5C" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Khs-Aw-6b7"/>
<constraint firstItem="loF-CI-n5C" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="cEr-al-Pib"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="loF-CI-n5C" secondAttribute="bottom" id="ftp-QG-OGJ"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="loF-CI-n5C" secondAttribute="trailing" id="num-9n-spN"/>
</constraints>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<point key="canvasLocation" x="138.40000000000001" y="153.37331334332833"/>
</view>
</objects>
</document>


ViewController:



override func viewDidLoad() {
super.viewDidLoad()

let collectionView = CustomCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 200), in: self, setCustomDelegate: true)
view.addSubview(collectionView)
}


Delegate Implementation:



extension ViewController: CustomCollectionViewDelegate {

func collectionViewDidScroll(_ scrollView: UIScrollView) {

//do something...
}
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 11 at 13:16

























answered Nov 11 at 8:25









Sateesh

1,354615




1,354615












  • You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
    – ilan
    Nov 11 at 9:07










  • Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
    – Sateesh
    Nov 11 at 13:20


















  • You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
    – ilan
    Nov 11 at 9:07










  • Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
    – Sateesh
    Nov 11 at 13:20
















You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
– ilan
Nov 11 at 9:07




You dont set the UIScrolllViewDelegate so scrollViewDidScroll wont be called
– ilan
Nov 11 at 9:07












Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
– Sateesh
Nov 11 at 13:20




Thats my bad. I'm sorry..!! After hitting my head so many times, I came to know that it is impossible to add delegate methods to generic UI elements as per MVC. But can be possible with customizing a UIView. I've updated my answer, please have a look.
– Sateesh
Nov 11 at 13:20


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244392%2fimplementing-uiscrollviewdelegate-in-a-uicollectionview-subclass%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Lugert, Oklahoma