Ios 8 Swift - TableView со встроенным CollectionView

Я относительно новичок в программировании на iOS и пробовал несколько вещей, но безрезультатно.

Я хотел бы поставить CollectionView внутри TableViewCell. Я могу кодировать каждый отдельно, но не понимаю, как устанавливать и ссылаться на каждый CollectionView в пределах TableViewCell.

Я нашел этот учебник http://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell/, который показывает, как это можно сделать в Objective-C, но я всегда боролся с Obj- С.

Кто-нибудь знает о Swift Tutorial или может помочь? Я нахожусь в процессе создания простого проекта/кода, который я отправлю в ближайшее время, чтобы попытаться помочь.

ИЗМЕНИТЬ 1

Я только что нашел быструю версию вышеупомянутой ссылки. Я сейчас работаю над этим, но кажется сложным, изменяя AppDelegate.

https://github.com/DahanHu/DHCollectionTableView

Большое спасибо Rob

Ответ 1

Создайте обычный UITableView и в UITableViewCell создайте UICollectionView. Ваш делегат collectionView и источник данных должны соответствовать этому UITableViewCell.

Просто пройдите через

В вашем ViewController

// Global Variable
var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

tableView = UITableView(frame: self.view.bounds)
    tableView.delegate = self
    tableView.dataSource = self
    self.view.addSubview(tableView)

    tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
    tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "NormalCell")
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 5
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 3 {
        var cell: TableViewCell = tableView.dequeueReusableCellWithIdentifier("TableViewCell", forIndexPath: indexPath) as! TableViewCell
        cell.backgroundColor = UIColor.groupTableViewBackgroundColor()
        return cell

    } else {
        var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("NormalCell", forIndexPath: indexPath) as! UITableViewCell
        cell.textLabel?.text = "cell: \(indexPath.row)"

        return cell
    }
}

Как вы можете видеть, я создал две разные ячейки - пользовательский TableViewCell, который возвращается только тогда, когда индекс строки равен 3 и базовый UITableViewCell в других индексах.

У пользовательского "TableViewCell" будет наш UICollectionView. Итак, создайте подкласс UITableViewCell и запишите приведенный ниже код.

import UIKit

class TableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {

var collectionView: UICollectionView!

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = UICollectionViewScrollDirection.Horizontal

    collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: layout)
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
    collectionView.backgroundColor = UIColor.clearColor()

    self.addSubview(collectionView)
}

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

// MARK: UICollectionViewDataSource
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    return 1
}


func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 10
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell: UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! UICollectionViewCell
    if indexPath.row%2 == 0 {
        cell.backgroundColor = UIColor.redColor()
    } else {
        cell.backgroundColor = UIColor.yellowColor()
    }

    return cell
}
}

Надеюсь, что это поможет.

Ответ 2

подробности

  • Xcode 10.2.1 (10E1001), Swift 5

Полный образец

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    fileprivate var tableViewCellCoordinator: [Int: IndexPath] = [:]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self
        tableView.tableFooterView = UIView()
    }
}

// UITableViewDataSource

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 5
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionViewTableViewCell") as! CollectionViewTableViewCell
        cell.selectionStyle = .none
        cell.collectionView.delegate = self
        cell.collectionView.dataSource = self

        let tag = tableViewCellCoordinator.count
        cell.collectionView.tag = tag
        tableViewCellCoordinator[tag] = indexPath

        return cell
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "section: \(section)"
    }

}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        let cell = cell as! CollectionViewTableViewCell
        cell.collectionView.reloadData()
        cell.collectionView.contentOffset = .zero
    }
}

// UICollectionViewDataSource

extension ViewController: UICollectionViewDataSource {

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell

        var text = ""
        if let indexPathOfCellInTableView = tableViewCellCoordinator[collectionView.tag] {
            text = "\(indexPathOfCellInTableView)"
        }
        cell.label.text = text + " \(indexPath)"
        return cell
    }
}

// UICollectionViewDelegate

extension ViewController: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("selected collectionViewCell with indexPath: \(indexPath) in tableViewCell with indexPath: \(tableViewCellCoordinator[collectionView.tag]!)")
    }
}

CollectionViewTableViewCell

import UIKit

class CollectionViewTableViewCell: UITableViewCell {

    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var collectionViewFlowLayout: UICollectionViewFlowLayout!
}

CollectionViewCell

import UIKit

class CollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var label: UILabel!
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_31582378" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="200" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="pS5-CW-ipl">
                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <prototypes>
                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="CollectionViewTableViewCell" id="bMP-Ac-C8D" customClass="CollectionViewTableViewCell" customModule="stackoverflow_31582378" customModuleProvider="target">
                                        <rect key="frame" x="0.0" y="28" width="375" height="200"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bMP-Ac-C8D" id="mcy-FO-bcc">
                                            <rect key="frame" x="0.0" y="0.0" width="375" height="199"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="yY4-ue-1HX">
                                                    <rect key="frame" x="8" y="8" width="359" height="183"/>
                                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="pPl-9q-MGc">
                                                        <size key="itemSize" width="180" height="180"/>
                                                        <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                                        <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                                        <inset key="sectionInset" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
                                                    </collectionViewFlowLayout>
                                                    <cells>
                                                        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="CollectionViewCell" id="g9z-R1-8XJ" customClass="CollectionViewCell" customModule="stackoverflow_31582378" customModuleProvider="target">
                                                            <rect key="frame" x="10" y="2" width="180" height="180"/>
                                                            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                                            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                                                <rect key="frame" x="0.0" y="0.0" width="180" height="180"/>
                                                                <autoresizingMask key="autoresizingMask"/>
                                                                <subviews>
                                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rHM-Xn-vBW">
                                                                        <rect key="frame" x="69" y="80" width="42" height="21"/>
                                                                        <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                                        <nil key="highlightedColor"/>
                                                                    </label>
                                                                </subviews>
                                                            </view>
                                                            <color key="backgroundColor" red="0.28627450980000002" green="0.56470588239999997" blue="0.8862745098" alpha="1" colorSpace="calibratedRGB"/>
                                                            <constraints>
                                                                <constraint firstItem="rHM-Xn-vBW" firstAttribute="centerX" secondItem="g9z-R1-8XJ" secondAttribute="centerX" id="AXf-f9-ruf"/>
                                                                <constraint firstItem="rHM-Xn-vBW" firstAttribute="centerY" secondItem="g9z-R1-8XJ" secondAttribute="centerY" id="gw4-Iv-7ML"/>
                                                            </constraints>
                                                            <size key="customSize" width="180" height="180"/>
                                                            <connections>
                                                                <outlet property="label" destination="rHM-Xn-vBW" id="9SL-Kv-ZtD"/>
                                                            </connections>
                                                        </collectionViewCell>
                                                    </cells>
                                                </collectionView>
                                            </subviews>
                                            <constraints>
                                                <constraint firstItem="yY4-ue-1HX" firstAttribute="bottom" secondItem="mcy-FO-bcc" secondAttribute="bottomMargin" id="04L-lF-Idy"/>
                                                <constraint firstItem="yY4-ue-1HX" firstAttribute="leading" secondItem="mcy-FO-bcc" secondAttribute="leadingMargin" id="Fjd-8j-qvK"/>
                                                <constraint firstItem="yY4-ue-1HX" firstAttribute="trailing" secondItem="mcy-FO-bcc" secondAttribute="trailingMargin" id="PUa-ze-U5s"/>
                                                <constraint firstItem="yY4-ue-1HX" firstAttribute="top" secondItem="mcy-FO-bcc" secondAttribute="topMargin" id="XX6-d1-Vgx"/>
                                            </constraints>
                                        </tableViewCellContentView>
                                        <connections>
                                            <outlet property="collectionView" destination="yY4-ue-1HX" id="tLL-Om-JIX"/>
                                            <outlet property="collectionViewFlowLayout" destination="pPl-9q-MGc" id="Ftw-AT-QvP"/>
                                        </connections>
                                    </tableViewCell>
                                </prototypes>
                            </tableView>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="pS5-CW-ipl" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="3vT-w2-JGU"/>
                            <constraint firstItem="pS5-CW-ipl" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="eS2-Y5-fxg"/>
                            <constraint firstItem="pS5-CW-ipl" firstAttribute="bottom" secondItem="wfy-db-euE" secondAttribute="top" id="hFA-oB-bWJ"/>
                            <constraint firstAttribute="trailing" secondItem="pS5-CW-ipl" secondAttribute="trailing" id="yin-cp-cAP"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="tableView" destination="pS5-CW-ipl" id="Gfe-HE-Ub6"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="136.80000000000001" y="137.18140929535232"/>
        </scene>
    </scenes>
</document>

Результаты

enter image description here enter image description here

Ответ 3

Подумайте о MVC и встраивании, никогда не программно подобном выше. Подкласс UIView (- > то, что есть на самом деле) никогда не является классом делегата для делегата и источника данных tableView (то же самое для коллекцииView).

Вы когда-либо создавали подкласс tableview, чтобы делать все программные вещи в этом подклассе - Нет! вы делаете это в своем viewcontroller - потому что вы создаете UIView в контроллерах, чтобы "контролировать" их. Так что вам нужно сделать правильный путь:

Позвольте мне привести пример (на пути к более понятному "старому школу" ):

  • Создайте ViewController с помощью tableView и добавьте (addSubview) эту коллекциюView в свой UITableViewCell.
  • У вас есть ViewController на раскадровке, а также UITableView встроенный
  • Он также связан с вашим классом ViewController как с выходом (и также его делегата и источника данных).
  • Вместо добавления CollectionView теперь в свой пользовательский UITableViewCell, просто добавьте UIView "контент-держатель" (с ограничениями). Позже вы будете использовать это представление для добавления коллекции в качестве подзапроса.

  • Теперь создайте новый UIViewController (новый файл > ...) с помощью XIB ИЛИ перетащите и отпустите новую панель UIViewController с панели свойств в своем раскадровки и создать также класс UIViewController. Не забывайте соединяйте друг друга. (мы сделаем первый для лучшего понимание)

  • Новый ViewController просто обрабатывает как ViewController с CollectionView (такой же, как 1. но collectionView).
  • В этом новом ViewController с collectionView вы обрабатываете все, как обычно, с делегатом и источником данных и т.д.

  • СЕЙЧАС: на ViewController (первый) с помощью tableView вы создать новый ViewController (с помощью collectionView) на каждом cell (cellForRowAtIndexPath) и добавьте его collectionView в качестве subview на текущий вид, который вы создали (как у владельца содержимого), например:.

let myViewControllerWithCollectionView = MyViewControllerWithCollectionView() myCell.contentHolderView.addSubview(myViewControllerWithCollectionView.collectionView)

Что вы также можете сделать (и, возможно, более новый и лучший способ, никогда не пробовали, но я уверен, что он будет работать очень хорошо, это: UIContainerView).

Вот оно! некоторые советы для вас:

  • будьте осторожны при добавлении нового subview в cellForRowAtIndexPath, проверьте всегда, если contentHolderView уже имеет

    myViewControllerWithCollectionView.collectionView

чтобы вернуть действия из коллекцииView, к текущему представлению добавьте пользовательский протокол (делегат) к вашему представлению для получения дополнительной информации. Никогда не устанавливайте делегат и источник данных из вашего коллекционного элемента в свой основной TableViewController, просто позвольте обрабатывать все на нужном диспетчере просмотра и выводить информацию на любой другой диспетчер представлений, если это необходимо.