реализация UIScrollViewDelegate в подклассе UICollectionView - PullRequest
0 голосов
/ 11 ноября 2018

У меня есть UICollectionView подкласс.

Я хочу добавить реализацию по умолчанию для scrollViewDidScroll из UIScrollViewDelegate

Есть ли способ получить доступ к методам делегата scrollView из подкласса UICollectionView?

Спасибо

Ответы [ 2 ]

0 голосов
/ 11 ноября 2018

Мы можем использовать концепцию 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...
    }
}
0 голосов
/ 11 ноября 2018

Вы можете добавить функцию, которая реализует код по умолчанию, который вам нужен, например:

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) {
        //...
    }
}

Затем, когда вы реализуете функции делегата в вашем контроллере представления, добавьте:

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

EDIT

Если вы хотите использовать свою коллекцию как внешнюю библиотеку и не хотите каждый раз вызывать обновленную функцию, вы можете реализовать пользовательский класс, который соответствует только UICollectionViewDelegate (если вы хотите иметь отдельный CustomDataSource класс, который реализует источник данных и делегат), например:

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 
}

Тогда в вашем контроллере представления вам просто нужно связать делегата с вашим контроллером представления:

class MyViewController: UIViewController {

    //...
    let customDelegate = YourCollectionViewDelegate()

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

    private func setupBindings() {

        customDelegate.onSelectedItemAt = { [weak self] indexPath in 
            //...
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...