Мы можем использовать концепцию delegation
для получения доступа от CustomCollectionView
всякий раз, когда пользователь его прокручивает.
Это реализация CustomCollectionView
, также обратите внимание, что метод delegate
имеет значение optional
, которые доступны в Objective C
.
Так что, если ваш ViewController
подтверждает CustomCollectionViewDelegate
protocol
, тогда ему нужно реализовать методы делегата, в противном случае он не должен.
Примечание:
Тем не менее, CustomCollectionView
является подклассом UICollectionView
означает его простой универсальный элемент пользовательского интерфейса. На самом деле это View
в Model-View-Controller (MVC)
. Согласно MVC
, View
нельзя напрямую разговаривать с Controller
, связь между View
и Controller
составляет blind & structured
. Хорошими примерами такого рода общения являются Target & Action
и delegate
pattern.
Делегат - это простая переменная, которая содержится в общих компонентах пользовательского интерфейса, таких как UIScrollView, UITableView, UICollectionView
и т. Д. Controller
должен подтвердить протокол, установив delegate
элемента пользовательского интерфейса в self
для реализации методы делегата внутри него.
Вывод: подкласс универсального элемента пользовательского интерфейса не может реализовать внутри него методы делегата.
Тем не менее, мы можем добиться этого, сделав пользовательский UIView
с XIB
и добавив к нему collectionView
.
Код:
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)
}
Реализация делегата:
extension ViewController: CustomCollectionViewDelegate {
func collectionViewDidScroll(_ scrollView: UIScrollView) {
//do something...
}
}