Swift iOS - 如何在单元格的 superView 中获取按钮的框架
Swift iOS -How to get frame of button inside cell's superView
我在视图控制器中有 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:
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)
}
}
在 UICollectionView
的 cellForItemAt
中尝试此代码
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)
}
在转换中使用 nil
导致了问题。我使用了应用程序的 window 并将其从 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)
}
}
在 class 中,您的 collectionView 符合委托
extension YourClass: YourCellDelegate {
func getReferenceTo(cell: UICollectionViewCell) {
// 6. get a reference to the main UIWindow
guard let window = UIApplication.shared.windows.first(where: { [=12=].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 }
}
}
我在视图控制器中有 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:
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)
}
}
在 UICollectionView
cellForItemAt
中尝试此代码
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)
}
在转换中使用 nil
导致了问题。我使用了应用程序的 window 并将其从 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)
}
}
在 class 中,您的 collectionView 符合委托
extension YourClass: YourCellDelegate {
func getReferenceTo(cell: UICollectionViewCell) {
// 6. get a reference to the main UIWindow
guard let window = UIApplication.shared.windows.first(where: { [=12=].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 }
}
}