【问题标题】:Accessing IBOutlet from subclass, outlets cannot be connected to repeating content subclass从子类访问 IBOutlet,outlet 无法连接到重复内容子类
【发布时间】:2020-10-17 23:14:49
【问题描述】:

我在 collectionviewcell 中嵌入了一个按钮,并研究了为什么“插座无法连接到重复内容子类”。我继续创建了一个具有 UICollectionViewCell 超类的子类。但是,我想通过视图控制器的 viewdidload 设置按钮的属性。我该怎么做?这是我的代码:

import UIKit

class Classic: UIViewController {

    override func viewDidLoad()
         {
             
        
         }
         
}
class Subclass: UICollectionViewCell{

    @IBOutlet weak var buttonOne: UIButton!
   
}

在我的图像中,左下角“collectionviewcell”中的按钮是我要操作的按钮

【问题讨论】:

  • 你可以使用闭包或委托
  • @jawadAli 我应该在哪里声明?你能给我一个例子吗?非常感谢!

标签: ios swift button viewcontroller collectionview


【解决方案1】:

您可以这样做,而不是在 viewDidLoad() 中获取按钮访问权限。在您的视图控制器类中创建一个 collectionView 的 @IBOutlet。

然后注册您的 UICollectionViewCell 的自定义子类,在您的情况下是它的“子类”

之后使用 collectionView 的 dataSource 方法加载单元格并访问按钮。

class Classic: UIViewController, UICollectionViewDataSource {

   @IBOutlet var collectionView: UICollectionView!
   override func viewDidLoad()
     {
        // Register your cell
        let nib = UINib(nibName: "Subclass", bundle: nil)
        collectionView?.registerNib(nib, forCellWithReuseIdentifier: "myCell")
     }     
    
    // Collection view data source method 
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     
    // get your cell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Subclass

      // here you will have access to your button
      cell.buttonOne.setTitle("Button Title", for: .normal)
       
     // To handle tap on button
     cell.buttonOne.tag = indexPath.row 
     cell.buttonOne.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)   

    return cell
}

    @objc func didTapButton(sender: UIButton) {
        print("button tapped at index:-", sender.tag)
    }
     
}

根据需要使用其他数据源和集合视图的委托。希望此解决方案对您有用。

【讨论】:

  • 您好,谢谢您的回复!!但是,当我尝试这段代码时,它问我“类型'Classic'不符合协议'UICollectionViewDataSource'你想添加协议存根吗?”,我应该添加这个协议存根吗?
  • @StevenOh 是的,请添加协议存根,它们是 UICollectionViewDataSource 的必需方法。
【解决方案2】:

您在cellForItemAt 中设置按钮属性(例如标题)。

旁注:使用Subclass 作为类名会非常混乱。

这是一个简单的例子:

class MyButtonCell: UICollectionViewCell{
    @IBOutlet weak var buttonOne: UIButton!
    
    var callback: (() -> ())?
    
    @IBAction func buttonTapped(_ sender: UIButton) {
        callback?()
    }
}

class TestCollectionViewController: UICollectionViewController {

    let buttonTitles: [String] = [
        "First", "Second", "Third", "etc..."
    ]

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return buttonTitles.count
    }
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCellID", for: indexPath) as! MyButtonCell
        cell.buttonOne.setTitle(buttonTitles[indexPath.item], for: [])
        cell.callback = {
            print("Button was tapped at \(indexPath)")
            // do what you want when the button is tapped
        }
        return cell
    }
}

请注意,我还为单元格子类内部 中的按钮添加了@IBAction。我还添加了这个 var / 属性:

var callback: (() -> ())?

这使得在您的控制器代码中设置closure 变得容易 - 再次在cellForItemAt 中设置 - 允许您的控制器在单元格中的按钮被点击时进行处理和操作。


编辑

这是一个完整的实现:

class MyButtonCell: UICollectionViewCell{
    @IBOutlet weak var buttonOne: UIButton!
    
    var callback: (() -> ())?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        contentView.layer.borderWidth = 1
        contentView.layer.borderColor = UIColor.black.cgColor
    }
    
    @IBAction func buttonTapped(_ sender: UIButton) {
        callback?()
    }
}

class StevenViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    let buttonTitles: [String] = [
        "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"
    ]
    
    @IBOutlet var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return buttonTitles.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCellID", for: indexPath) as! MyButtonCell

        // set the button title (and any other properties)
        cell.buttonOne.setTitle(buttonTitles[indexPath.item], for: [])

        // set the cell's callback closure
        cell.callback = {
            print("Button was tapped at \(indexPath)")
            // do what you want when the button is tapped
        }

        return cell
    }
}

这里是 Storyboard 源代码 - 如果您以前没有这样做过,请创建一个新的 Storyboard,选择 Open As -> Source Code,删除那里的内容,复制并粘贴以下内容...然后您可以选择 Open As -> Interface Builder -Storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="81J-PL-nYH">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="collection view cell content view" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Steven View Controller-->
        <scene sceneID="UOc-kB-D4u">
            <objects>
                <viewController id="81J-PL-nYH" customClass="StevenViewController" customModule="FirstNewMini" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="5pE-V8-AOY">
                        <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="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="eKk-rE-Fyn">
                                <rect key="frame" x="20" y="567" width="335" height="60"/>
                                <color key="backgroundColor" red="0.99942404029999998" green="0.98555368190000003" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="60" id="t8R-1V-ELi"/>
                                </constraints>
                                <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" automaticEstimatedItemSize="YES" minimumLineSpacing="10" minimumInteritemSpacing="10" id="34u-td-lg8">
                                    <size key="itemSize" width="60" height="60"/>
                                    <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>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="myCellID" id="slK-WV-d6z" customClass="MyButtonCell" customModule="FirstNewMini" customModuleProvider="target">
                                        <rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                        <collectionViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="inr-uV-Mkf">
                                            <rect key="frame" x="0.0" y="0.0" width="60" height="60"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jO2-43-Y97">
                                                    <rect key="frame" x="7" y="15" width="46" height="30"/>
                                                    <color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <state key="normal" title="Button"/>
                                                    <connections>
                                                        <action selector="buttonTapped:" destination="slK-WV-d6z" eventType="touchUpInside" id="ILI-g9-h3v"/>
                                                    </connections>
                                                </button>
                                            </subviews>
                                            <constraints>
                                                <constraint firstItem="jO2-43-Y97" firstAttribute="centerY" secondItem="inr-uV-Mkf" secondAttribute="centerY" id="K8s-Jl-sfY"/>
                                                <constraint firstItem="jO2-43-Y97" firstAttribute="centerX" secondItem="inr-uV-Mkf" secondAttribute="centerX" id="kF4-R0-H31"/>
                                            </constraints>
                                        </collectionViewCellContentView>
                                        <connections>
                                            <outlet property="buttonOne" destination="jO2-43-Y97" id="EkG-Dz-2DC"/>
                                        </connections>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <constraints>
                            <constraint firstItem="OxZ-Gp-ekf" firstAttribute="trailing" secondItem="eKk-rE-Fyn" secondAttribute="trailing" constant="20" id="Gua-Zi-IFQ"/>
                            <constraint firstItem="OxZ-Gp-ekf" firstAttribute="bottom" secondItem="eKk-rE-Fyn" secondAttribute="bottom" constant="40" id="I6q-K5-nN3"/>
                            <constraint firstItem="eKk-rE-Fyn" firstAttribute="leading" secondItem="OxZ-Gp-ekf" secondAttribute="leading" constant="20" id="sCP-Nn-RqH"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="OxZ-Gp-ekf"/>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="eKk-rE-Fyn" id="rxw-DZ-Kpi"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="Ap0-Qs-M9q" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="199.19999999999999" y="155.17241379310346"/>
        </scene>
    </scenes>
</document>

你运行它的结果应该是这样的(我给集合视图一个黄色背景以便于看到框架):

【讨论】:

  • 嘿,我试图实现这个,但你能解释一下我如何使用你写的函数吗?非常感谢!
【解决方案3】:
  • 从情节提要添加 CollectionView 出口
  • cellForItemAtIndexPath 中添加按钮点击块
import UIKit

class Classic: UIViewController {

    @IBoutlet weak var collectionView : UICollectionView

    override func viewDidLoad() {
             
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(SubClass.self, forCellWithReuseIdentifier: "cell")
    }
         
}

extension Classic : UICollectionViewDelegate {

}

extension Classic : UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)

        cell.buttonTapped = {
            print("Button Tapped")
        }

        return cell
    }
}

class Subclass: UICollectionViewCell{

    @IBOutlet weak var buttonOne: UIButton!

    var buttonTapped : () -> () = { }

    @IBAction func buttonTapped(_ sender: UIButton) {
        self.buttonTapped()
     }
   
}





【讨论】:

    猜你喜欢
    • 2018-08-12
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2018-07-22
    • 2014-04-17
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多