iOS 增加 UITableViewCell 中 UIButton 的触控区域

Posted

技术标签:

【中文标题】iOS 增加 UITableViewCell 中 UIButton 的触控区域【英文标题】:iOS increase touch area for UIButton in TableViewCell 【发布时间】: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之外的地方,我就会触摸到表格单元格。

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

【问题讨论】:

如果没有问题,增加按钮的宽度/高度。单元格的其他子视图是什么? 【参考方案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),它的大小小于按钮大小

【讨论】:

以上是关于iOS 增加 UITableViewCell 中 UIButton 的触控区域的主要内容,如果未能解决你的问题,请参考以下文章

需要双向展开uitableviewcell

Xcode 7 iOS 9 UITableViewCell 分隔符插入问题

如何在自定义 UITableViewCell 中增加 Label 的高度

在分组的 TableView 布局中增加 UITableViewCell 的宽度

根据子WebView iOS增加单元格高度

如何增加 UItableviewcell 内的 UItableview 高度?