【问题标题】:Swift iOS -How to get frame of button inside cell's superViewSwift iOS - 如何在单元格的 superView 中获取按钮框架
【发布时间】:2018-07-12 13:20:00
【问题描述】:

我在视图控制器中有 collectionView。在 collectionView 单元格内,我有一个按钮。由于将有几个单元格,每个按钮在 vc 中都有不同的位置。 点击按钮时,如何在 ViewController(而不是 collectionView)中获取按钮的框架?我想从单元格本身而不是 cellForItem 中获取它。

无论我在任何单元格内点击哪个按钮,我都在下面尝试过,但它总是打印出(0.0, 64.0, 0.0, 0.0)

@objc func myButtonTapped() {
    let locationInSuperView = self.convert(myButton.frame, to: nil)
    print(locationInSuperView)
}

代码如下:

CollectionViewCell:

class MyCell: UICollectionViewCell{

    lazy var myButton: UIButton = {
        let button = UIButton(type: .system)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setImage(UIImage(named: "myButton"), for: .normal)
        button.addTarget(self, action: #selector(myButtonTapped), for: .touchUpInside)
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = .white

        contentView.addSubview(myButton)
        myButton.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -8).isActive = true
        myButton.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
        myButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
        myButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
    }

    @objc func myButtonTapped() {

        let locationInSuperView = self.superview!.convert(myButton.frame, to: nil)
        print(locationInSuperView)
    }
}

视图控制器:

ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    var collectionView: UICollectionView!
    let myCell = "myCell"

    override func viewDidLoad() {
        super.viewDidLoad()

        let layout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
        layout.scrollDirection = .vertical

        collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(MyCell.self, forCellWithReuseIdentifier: myCell)
        view.addSubview(collectionView)
    }

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

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

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: view.frame.width, height: 50)
    }
}

【问题讨论】:

  • 为什么你在convert中使用nil?
  • @Kerberos 你对 nil 的看法是正确的,谢谢

标签: ios swift uicollectionviewcell cgrect superview


【解决方案1】:

UICollectionViewcellForItemAt 中尝试此代码

cell.myButton.addTarget(self, action: #selector(myButtonTapped), for: .touchUpInside)

@objc func myButtonTapped(_ sender: UIButton) {
    let buttonPosition : CGPoint = sender.convert(sender.bounds.origin, to: self.collectionView)
}

【讨论】:

    【解决方案2】:

    在转换中使用 nil 会导致问题。我使用了应用程序的窗口,将其从 nil 切换到 window,问题就解决了。

    @objc func myButtonTapped() {
    
        if let window = UIApplication.shared.keyWindow {
            
            let locationInWindow = self.convert(myButton.frame, to: window)
            print(locationInWindow)
        }
    }
    

    更新:

    我找到了另一种方法。这有点复杂,但它有效

    // 1. use delegation inside the cell
    protocol YourCellDelegate: class {
        func getReferenceTo(cell: YourCell)
    }
    
    class YourCell: UICollectionViewCell {
    
        lazy var someButton: UIButton = {
            // ...
        }()
    
        // 2. wherever you add someButton to the cell make sure it is a child of the cell's contentView
        func setAnchors() {
    
            self.contentView.addSubview(someButton)
            // set the x,y,w,h for the button
        }
    
        // 3. call the delegate in layoutSubviews
        override func layoutSubviews() {
            super.layoutSubviews()
    
            // 4. *** SUPER IMPORTANT *** call contentView.layoutIfNeeded() first
            contentView.layoutIfNeeded()
    
            // 5. second call your delegate method here after calling contentView.layoutIfNeeded()
            delegate?.getReferenceTo(cell: self)
        }
    }
    

    在你的 collectionView 符合 to delegate 的类中

    extension YourClass: YourCellDelegate {
    
        func getReferenceTo(cell: UICollectionViewCell) {
    
            // 6. get a reference to the main UIWindow
            guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }
    
            // 7. get a reference to the button from the cell
            let someButton = cell.someButton
    
            // 8. call convert(_:) using the window, the button's frame, and the cell's contentView (make sure that the button is a subview of the cell's contentView and not the cell itself -step 2.)
            let buttonFrameInWindow = window.convert(someButton, from: cell.contentView)
    
            print(buttonFrameInWindow) // will print the button's CGRect in the UIWindow x,y,w,h { 100, 400, 40, 40 }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多