【问题标题】:iOS increase touch area for UIButton in TableViewCelliOS 增加 UITableViewCell 中 UIButton 的触控区域
【发布时间】:2015-10-13 11:38:59
【问题描述】:

我的UITableViewCell 中有一个UIButton

我创建了UIButton 的子类覆盖pointInside 函数:

var touchMargin:CGFloat = 20.0

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    let extendedArea = CGRectInset(self.bounds, -touchMargin, -touchMargin)
    return CGRectContainsPoint(extendedArea, point)
}

但是,触摸区域并没有增加。
如果我稍微触摸UIButton之外的地方,我就会触摸到表格单元格。

由于按钮被放置在单元格中,此代码是否不起作用?
我该如何解决?

【问题讨论】:

  • 如果没有问题,增加按钮的宽度/高度。单元格的其他子视图是什么?

标签: ios swift uitableview uibutton


【解决方案1】:

斯威夫特 3

//
//  ViewController.swift
//  test
//
//  Created by David Seek on 9/29/16.
//  Copyright © 2016 David Seek. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = MyButton(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
        button.backgroundColor = UIColor.white
        button.addedTouchArea = 50 // any value you want
        button.addTarget(self, action:#selector(self.action), for: .touchUpInside)
        self.view.addSubview(button)
    }

    func action() {
        print("touched")
    }

}

class MyButton: UIButton {
    var addedTouchArea = CGFloat(0)

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

        let newBound = CGRect(
            x: self.bounds.origin.x - addedTouchArea,
            y: self.bounds.origin.y - addedTouchArea,
            width: self.bounds.width + 2 * addedTouchArea,
            height: self.bounds.width + 2 * addedTouchArea
        )
        return newBound.contains(point)
    }
}

您正在创建一个尺寸为 100x100 的 UIButton,而使用 .addedTouchArea,您将拥有一个 UIButton - 光学尺寸仍为 100x100,但触摸区域为 150x150。

Swift 2.X

class MyButton: UIButton {
    var addedTouchArea = CGFloat(0)

    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {

        let newBound = CGRect(
            x: self.bounds.origin.x - addedTouchArea,
            y: self.bounds.origin.y - addedTouchArea,
            width: self.bounds.width + 2 * addedTouchArea,
            height: self.bounds.width + 2 * addedTouchArea
        )
        return newBound.contains(point)
    }
}

界面生成器

如果您确实使用InterfaceBuilder 设置了按钮,请将我们的UIButton 子类应用于您的按钮。

然后为按钮设置一个出口,f.e.命名按钮XY。并将buttonXY.addedTouchArea = 50 设置在viewDidLoad 内,f.e.

UITableViewCell

因为您要求UITableViewCell。它的工作原理完全相同。

在您的 ViewController 类中:

extension ViewController: UITableViewDelegate, UITableViewDataSource {

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

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell") as! TableViewCell
        cell.selectionStyle = UITableViewCellSelectionStyle.none

        cell.myButton.addedTouchArea = 50 // any value you want
        tableView.rowHeight = 200

        return cell
    }
}

在您的 Cell 类中:

class TableViewCell: UITableViewCell {

    @IBOutlet weak var myButton: MyButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

    @IBAction func myButtonAction(_ sender: AnyObject) {
        print("touched")
    }
}

唯一需要注意的是:插座被设置为UIButton 插座,即使我在InterfaceBuilder 中将其声明为 MyButton 的子类。我不得不手动将插座更改为MyButton@IBOutlet weak var myButton: MyButton!

【讨论】:

  • 当您设置了 didSelectRowAtIndexPath 时,当您点击单元格时,表格视图是否不会进行选择。
  • 没有。我已经在我的一个大项目以及一个像这样的项目中使用它来为你测试它。如果您点击按钮,不会触发 didSelectRowAtIndexPath。如果您点击按钮的点击区域以外的单元格,didSelectRowAtIndexPath 将 - 当然 - 被触发
  • @user694688 有什么消息吗?
  • 如果按钮在堆栈视图中怎么办。
  • 赏金怎么了?
【解决方案2】:

您应该在要放大的视图上覆盖 hitTest。

例如

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
        return nil;
    }
    CGRect touchRect = CGRectInset(self.bounds, -10, -10);
    if (CGRectContainsPoint(touchRect, point)) {
        //TODO!? check supviews
        return self;
    }
    return nil;
}

【讨论】:

    【解决方案3】:

    首先你需要创建 UIButton 子类:

    class ButtonWithTouchSize: UIButton {
    
        var touchAreaPadding: UIEdgeInsets? = nil
    
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            if let inset = touchAreaPadding {
                let origin = CGPoint(x: 0 - inset.left, y: 0 - inset.top)
                let size = CGSize(width: inset.left + bounds.width + inset.right,
                                  height: inset.top + bounds.height + inset.bottom)
                let rect = CGRect(origin: origin, size: size)
                return rect.contains(point)
            } else { 
                return super.point(inside: point, with: event)
            }
        }
    }
    

    如果你把一个ButtonWithTouchSize 的实例直接放到UITableViewCell contentView 中,你会得到它。但是,如果您将此实例包装在 UITableViewCell contentView 中的某个容器中,您还应该覆盖它的 point(inside:with) 方法:

    class ContainerView: UIView {
    
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            return btn.point(inside: point, with: event)
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
            btn.frame = self.bounds
        }
    
        private let btn: ButtonWithTouchSize = ButtonWithTouchSize()
    
    }
    

    所以,总而言之……你应该为每个超级视图覆盖 point(inside:with),它的大小小于按钮大小

    【讨论】:

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