从集合视图中的可重用单元格中获取按钮单击(xib文件)

时间:2017-07-04 13:59:09

标签: ios swift swift3

我创建了可重复使用的单元格,在XIB中包含了一个用于集合的按钮。

我可以在集合视图中更改标签和按钮的文字,但我无法点击事件。

我尝试过以下选项:

一个。这在UICollectionViewCell中:不工作

first-field-is-required | second-field-is-required | ... | hundredth-field-is-required

湾我也尝试过:不工作

class cellVC: UICollectionViewCell {
    @IBOutlet weak var sampleLabel: UILabel!
    @IBOutlet weak var buttonClicked: UIButton!

    @IBAction func buttonTest(_ sender: Any) {
        print("dsfsdf   111111")
    }
}

由于两种解决方案都不起作用,我如何实现这一目标。

由于

5 个答案:

答案 0 :(得分:2)

而不是

 cell.buttonClicked.addTarget(self, action: #selector(masterAction(sender:)), for: .touchUpInside)

 cell.buttonClicked.addTarget(self, action: #selector(masterAction(_:)), for: .touchUpInside)

答案 1 :(得分:2)

要检查的地方

这里有几个潜在的失败点,因为你正在做的似乎看起来正确。我有一个示例Xcode项目,它有这个工作。 (见GitHub上的。)

您可以仔细检查这些内容,以确保所有内容都设置正确:

  • 您的集合视图的数据源和代理已连线
  • 您的按钮和样品标签的插座连接正确
  • 您的故事板已设置相应的类和标识符
  • 您的选择器名称正确

根据您在此处发布的所有上述条件都是正确的,似乎让我们更多地谈谈您尝试做什么,看看所有情况如何件适合。

为什么这些事情好不好

  • 如果数据源和代理设置不正确,您将无法看到您的单元格。
  • 如果你的网点连接错误,你最终会崩溃,因为IBOutlets默认是强制解包。 (那就是你发布的代码是如何工作的。)
  • 您的故事板似乎设置正确,因为如果没有正确的设置,您的单元格也不会出现。
  • 错误命名的选择器甚至无​​法编译。

细胞和回收的含义

一般来说,由于UICollectionView的设计方式,这是一个难以解决的问题。 (这同样适用于UITableView。)

您的按钮位于可重复使用的集合视图单元格内,这意味着您不仅需要处理点击,还需要知道按钮当前所指的数据集中的索引路径。

此外,放置在UICollectionViewCell实例中的视图实际上位于集合视图单元格contentView内部,这使得它只需要处理一些工作。

最后,如果您的单元格在屏幕上和屏幕外滚动,那么当单元格被回收时,您可能会多次将操作附加到按钮上。所以,你也需要考虑到这一点。

实施例

让我们使用一个非常简单的自定义单元格,其中只有一个按钮: An image of a collection view cell with a single centered button.

按钮的代码如下所示:

import UIKit

class CustomCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var updateButton: UIButton!
}

真的很简单。请注意IBOutlet。这也需要在界面构建器中连接起来。

An image of the Xcode inspector, showing the button wired up to its outlet

我们需要做的最后一件事是设置单元格的重用标识符,以便我们可以在代码中访问它。在Interface Builder中选择单元格后,向单元格添加标识符:

A screenshot of Xcode inspector, showing a collection view cell's identifier

好的,这就是你需要对细胞做的所有事情。我们已准备好实施视图控制器。在视图控制器中,我们将设置一些内容:

  1. 显示我们按钮内的按钮的标签
  2. 我们的集合视图的出口,因此我们可以获取包含该按钮的单元格的索引路径。 (如果您使用的是UICollectionViewController而不是UIViewController,则无需使用此功能。)
  3. 显示我们自定义单元格的一些代码。
  4. 处理按钮的一些代码。
  5. 让我们从IBOutlets开始:

    class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    
        @IBOutlet weak var lastTappedLabel: UILabel!
        @IBOutlet weak var collectionView: UICollectionView!
    

    我们需要在“界面”构建器中连接它们。当您正在使用它时,连接集合视图的数据源并委托成为"文件的所有者"如果他们还没有连接。 (同样,如果您使用的是UICollectionViewController而不是UIViewController,那么这将是必要的。)

    接下来,让我们使用UICollectionViewDataSource实现一些代码以显示我们的自定义单元格。我们需要显示至少一个部分和至少一个单元格:

    // MARK: - UICollectionViewDataSource
    
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 36
    }
    

    当我们将单元格出列时,我们希望将我们出列的单元格向下转换为我们之前定义的自定义单元格类。然后我们可以访问更新按钮以向其添加操作。

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "com.mosheberman.samples.cell", for: indexPath) as! CustomCollectionViewCell
    
        cell.updateButton.addTarget(self, action: #selector(updateLabel(_:)), for: .touchUpInside)
    
        return cell
    }
    

    现在我们需要实现访问单元索引路径的方法:

    // MARK: - Updating the Label
    
    @objc func updateLabel(_ sender:UIButton)
    {
        print("\(sender) tapped. Update label called.")
    
        guard let button = sender as? UIButton else
        {
            print("Sender isn't a button. Returning.")
            return
        }
    
        guard let contentView = button.superview else
        {
            print("Button isn't inside a contentView. Returning.")
            return
        }
    
        guard let cell = contentView.superview as? UICollectionViewCell else
        {
            print("View's superview isn't a UICollectionViewCell instance. Returning.")
            return
        }
    
        guard let collectionView = self.collectionView else
        {
            print("Our collection view isn't wired up. Returning.")
            return
        }
    
        guard let indexPathForCell = collectionView.indexPath(for: cell) else
        {
            print("The cell doesn't correspond to an index path. Maybe it's not a child of this collection view?")
            return
        }
    
        self.lastTappedLabel.text = "Tapped button at \(indexPathForCell.item), \(indexPathForCell.section)"
    }
    

    此方法处理处理点击所需的所有检查,并确定实际点击了哪个项目。

    1. 我们需要确保sender实际上是UIButton个实例。并不重要,但如果我们至少确保它不是UIView,我们就无法获得superview
    2. 完成后,请确保该按钮位于superview内,我们假设该contentViewCustomCollectionViewCell
    3. 检查内容视图的超级视图,我们将自己拥有该单元格。
    4. 此时我们可以询问集合视图(由于上面设置的插座,我们有一个参考),指向单元格的索引路径。
    5. 一旦我们有了索引路径,我们就可以更新我们的标签,或者使用支持单元格的数据做一些事情。
    6. 注释

      • 在测试时我发现你可能实际上不再需要删除目标动作了 - 现在UIKit似乎做了正确的事情,只调用你的方法一次。
      • 我们在这里写的代码可用on GitHub

      修改

      @DonMag指出你正在使用笔尖而不是故事板,我最初忽略了这一点。所以,这是使用笔尖设置所有内容的过程:

      1. 我们可以使用与上面相同的单元类,但我们需要为它添加一个单独的nib,因为视图控制器nib不支持单元原型。
      2. 出于同样的原因,我们需要单独注册笔尖。在故事板中包含单元格原型会自动执行此操作。使用笔尖时,您无法免费获得此笔。
      3. 我们需要在笔尖中设置视图控制器。
      4. 几乎所有其他代码都可以从故事板版本移出。
      5. 让我们为CustomViewControllerCell创建一个新的笔尖。使用"空"模板,创建一个名为" CustomCollectionViewCell.xib的新笔尖。"该名称不必与该类匹配,但它将在以后使用,因此为了遵循惯例,我们将其称之为。

        在新的笔尖中,从右下角的调色板中拖出一个集合视图单元格,然后将标签添加到它。将自定义类设置为UIViewController(或称为您的自定义类)并将标签连接到插座。

        接下来,让我们制作一个新的View Controller。我们可能可以重复使用最初的一个,但是为了不为相同的标识符注册两个单元格,让我们坚持使用新的registerCollectionViewCell()子类。要获取笔尖,请选中"还要创建XIB文件。"

        在新的基于nib的视图控制器中,我们需要与之前相同的插座。我们还想要相同的UICollectionViewDataSource实现。这里有一点不同:我们需要注册单元格。

        为此,请添加一个名为viewDidLoad的方法,我们将从// MARK: - Setting Up The Collection View Cell func registerCollectionViewCell() { guard let collectionView = self.collectionView else { print("We don't have a reference to the collection view.") return } let nib = UINib(nibName: "CustomCollectionViewCell", bundle: Bundle.main) collectionView.register(nib, forCellWithReuseIdentifier: "com.mosheberman.samples.cell") } 拨打该方法。这是它的样子:

        viewDidLoad()

        我们的override func viewDidLoad() { super.viewDidLoad() self.registerCollectionViewCell() // Do any additional setup after loading the view. } 方法现在看起来像这样:

        application(_:didFinishLaunchingWithOptions:)

        在笔尖内部,像我们之前一样布置标签和集合视图。连接出口和集合视图数据源,并委托,我们应该完成!

        其他一些事情:

        • 在我的演示项目中,我还需要提供基于nib的视图控制器版本。我通过替换NSObject
        • 中加载的应用程序主要故事板,在应用程序委托中完成了
        • 您的故事板笔尖应将文件所有者保留为默认值{{1}}。单元格应该有一个自定义类,可以匹配您要加载的任何类。

答案 2 :(得分:1)

当按钮链接到文件所有者而不是您的单元格时,有时会发生这种情况。

右键单击IB中的按钮并检查引用插座是否正确,这应该是您的单元格而不是文件所有者,如下图所示:

enter image description here

答案 3 :(得分:0)

你可以选择:



private void button6_Click(object sender, EventArgs e)
{
    DialogResult result = openFileDialog2.ShowDialog();
    if (result == DialogResult.OK)
    {
        string file = openFileDialog2.FileName;
        try
        {
            string text = File.ReadAllText(file);
        }
        catch (IOException)
        {
        }
    }
}

private void button5_Click(object sender, EventArgs e)
{
    //Search from selected .txt file like: ("a"), ("b"), ("c")
}




答案 4 :(得分:0)

感谢@Thomas如果有人想要解决方案,那么最上面的答案已经迅速更新:

self.contentView.isUserInteractionEnabled = false