Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 为什么UIButton使用触摸而不是UIControl 我在表格视图单元格中有一些自定义按钮 这些按钮包含在另一个视图中,该视图不占用整个单元格 我希望按钮总是对点击做出响应(并使用点击,以便不同时选择单元格) 我希望我的按钮容器视图使用不在按钮本身上的点击(以便不选择单元格) 我想在我的按钮容器外的单元格中的任何位置,按常规选择单元格_Ios_Objective C_Swift_Uibutton_Uicontrol - Fatal编程技术网

Ios 为什么UIButton使用触摸而不是UIControl 我在表格视图单元格中有一些自定义按钮 这些按钮包含在另一个视图中,该视图不占用整个单元格 我希望按钮总是对点击做出响应(并使用点击,以便不同时选择单元格) 我希望我的按钮容器视图使用不在按钮本身上的点击(以便不选择单元格) 我想在我的按钮容器外的单元格中的任何位置,按常规选择单元格

Ios 为什么UIButton使用触摸而不是UIControl 我在表格视图单元格中有一些自定义按钮 这些按钮包含在另一个视图中,该视图不占用整个单元格 我希望按钮总是对点击做出响应(并使用点击,以便不同时选择单元格) 我希望我的按钮容器视图使用不在按钮本身上的点击(以便不选择单元格) 我想在我的按钮容器外的单元格中的任何位置,按常规选择单元格,ios,objective-c,swift,uibutton,uicontrol,Ios,Objective C,Swift,Uibutton,Uicontrol,为此,我在buttons容器视图上附加了一个手势识别器 只要我的按钮是ui按钮s(即点击按钮本身会导致按钮上出现TouchUpInside事件,点击按钮容器中的任何其他位置都不会产生任何效果,点击按钮容器外单元格中的任何其他位置都会导致选中单元格)。但是,如果我使用UIControl而不是ui按钮,则不再是这种情况-控件从不响应点击(按钮容器始终使用点击,点击按钮容器外部的单元格会导致选中单元格)。需要注意的是,如果我没有将手势识别器添加到按钮容器中,则控件会以与ui按钮相同的方式响应点击 我唯

为此,我在buttons容器视图上附加了一个手势识别器

只要我的按钮是
ui按钮
s(即点击按钮本身会导致按钮上出现
TouchUpInside
事件,点击按钮容器中的任何其他位置都不会产生任何效果,点击按钮容器外单元格中的任何其他位置都会导致选中单元格)。但是,如果我使用
UIControl
而不是
ui按钮
,则不再是这种情况-控件从不响应点击(按钮容器始终使用点击,点击按钮容器外部的单元格会导致选中单元格)。需要注意的是,如果我没有将手势识别器添加到按钮容器中,则控件会以与
ui按钮
相同的方式响应点击

我唯一的解释是,
UIButton
(继承自
UIControl
)以某种方式添加了一些额外的触摸处理。在这种情况下,我想知道它做什么以及应该如何模拟它(我需要使用
UIControl
而不是
UIButton
,因为我的按钮有一个自定义视图层次结构,我不想在
UIButton
中玩它)

以下视图控制器代码应允许任何人重现该问题:

class ViewController: UITableViewController, UIGestureRecognizerDelegate {

    lazy var containerView: UIView = {
        let view: UIView = UIView()
        view.backgroundColor = UIColor.redColor()
        view.setTranslatesAutoresizingMaskIntoConstraints(false)
        view.addSubview(self.buttonContainerView)
        view.addConstraints([
            NSLayoutConstraint(item: self.buttonContainerView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.LeadingMargin, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: self.buttonContainerView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TrailingMargin, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: self.buttonContainerView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: self.buttonContainerView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1.0, constant: 0.0)
        ])

        return view
    }()

    lazy var buttonContainerView: UIView = {
        let view: UIView = UIView()
        view.backgroundColor = UIColor.blueColor()
        view.setTranslatesAutoresizingMaskIntoConstraints(false)
        view.addSubview(self.control)
        view.addSubview(self.button)
        view.addConstraints([
            NSLayoutConstraint(item: self.control, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 0.5, constant: 0.0),
            NSLayoutConstraint(item: self.control, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterY, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: self.button, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1.5, constant: 0.0),
            NSLayoutConstraint(item: self.button, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterY, multiplier: 1.0, constant: 0.0)
        ])

        return view
    }()

    lazy var control: UIControl = {
        let view: UIControl = TestControl(frame: CGRectZero)
        view.addTarget(self, action: Selector("controlTapped:"), forControlEvents: UIControlEvents.TouchUpInside)

        return view
    }()

    lazy var button: UIButton = {
        let view: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
        view.setTitle("Tap button", forState: UIControlState.Normal)
        view.setTranslatesAutoresizingMaskIntoConstraints(false)
        view.addTarget(self, action: Selector("buttonTapped:"), forControlEvents: UIControlEvents.TouchUpInside)

        return view
    }()

    func controlTapped(sender: UIControl) -> Void {
        println("Control tapped!")
    }

    func buttonTapped(sender: UIButton) -> Void {
        println("Button tapped!")
    }

    var recogniser: UITapGestureRecognizer?
    var blocker: UITapGestureRecognizer?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.rowHeight = 200.0

        self.containerView.layoutMargins = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)

        let recogniser: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("tappedContainer:"))
        recogniser.delegate = self
        self.recogniser = recogniser

        self.containerView.addGestureRecognizer(recogniser)

        let blocker: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("tappedBlocker:"))
        blocker.delegate = self
        self.blocker = blocker

        self.buttonContainerView.addGestureRecognizer(blocker)
    }

    func tappedContainer(recogniser: UIGestureRecognizer) -> Void {
        println("Tapped container!")
    }

    func tappedBlocker(recogniser: UIGestureRecognizer) -> Void {
        println("Tapped blocker!")
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let identifier: String = "identifier"
        let cell: UITableViewCell
        if let queuedCell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(identifier) as? UITableViewCell {
            cell = queuedCell
        }
        else {
            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: identifier)

            cell.contentView.layoutMargins = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
            cell.contentView.backgroundColor = UIColor.purpleColor()

            cell.contentView.addSubview(self.containerView)

            cell.contentView.addConstraints([
                NSLayoutConstraint(item: self.containerView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.LeadingMargin, multiplier: 1.0, constant: 0.0),
                NSLayoutConstraint(item: self.containerView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.TrailingMargin, multiplier: 1.0, constant: 0.0),
                NSLayoutConstraint(item: self.containerView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.TopMargin, multiplier: 1.0, constant: 0.0),
                NSLayoutConstraint(item: self.containerView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1.0, constant: 0.0)
            ])
        }

        return cell
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
        println("selected cell")
    }

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

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
}

class TestControl: UIControl {
    override init(frame: CGRect) {
        super.init(frame: frame)

        let view: UIControl = self

        let label: UILabel = UILabel()
        label.text = "Tap control"
        label.userInteractionEnabled = false

        view.layer.borderColor = UIColor.orangeColor().CGColor
        view.layer.borderWidth = 2.0
        view.setTranslatesAutoresizingMaskIntoConstraints(false)
        label.setTranslatesAutoresizingMaskIntoConstraints(false)

        view.addSubview(label)
        view.addConstraints([
            NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.TopMargin, multiplier: 1.0, constant: 5.0),
            NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.GreaterThanOrEqual, toItem: view, attribute: NSLayoutAttribute.LeadingMargin, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: label, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.LessThanOrEqual, toItem: view, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1.0, constant: 0.0)
        ])
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
编辑

明确地说,我并不是在寻找一种“只起作用”的替代解决方案——我想了解这种差异是什么,我应该做些什么来模仿它,或者可能是另一种语义正确的方法

我唯一的解释是UIButton(从UIControl继承)以某种方式添加了一些额外的触摸处理

你是对的,UIButton是特殊的。不久前我在回答问题时做了一些研究,在“与其他用户界面控件交互”一节中提到了按钮事件触发的原因:

在iOS 6.0及更高版本中,默认控制动作可防止手势识别器行为重叠。例如,按钮的默认操作是单次点击。如果在按钮的父视图上附加了一个点击手势识别器,并且用户点击了按钮,则按钮的动作方法接收触摸事件,而不是手势识别器

然后,它列出了一些示例,其中一个示例就是用手指轻触
ui按钮

与默认控件一样,阻止手势识别器的方法是使用
TestControl
覆盖
gesturecognizer应该开始:
(请参阅)。如果您想模仿
UIButton
的行为,可以使用以下方法:

override func GestureRecognitizer应开始(GestureRecognitizer:UIGestureRecognitizer)->Bool{
如果让tapGestureRecognizer=gestureRecognizer作为?UITapGestureRecognizer{
如果tapGestureRecognizer.numberOfTapsRequired==1&&tapGestureRecognizer.numberOfTouchesRequired==1{
返回false;
}
}
返回true;
}

感谢您的解释和链接-苹果似乎告诉我们,
UIButton
是一个例外(但没有告诉我们如何实现类似行为)。您建议的代码工作得非常完美,但是,我想了解原因,并确保它不容易更改
UIControl
不声明
UIGestureRecognitizerDelegate
一致性,那么我是否有效地覆盖了隐藏手势识别器的私有方法?@Rupert
GestureRecognitizer应该开始:
实际上是
UIView
上的一个方法(它是
UIControl
继承的),因此不涉及任何隐藏的或私有的API。我刚刚在中仔细检查了该方法的文档,它注意到,
UISlider
使用它来阻止某些刷卡手势,因此这是处理这些情况的官方方法(我将更新我的答案以说明这一点)。@cszucko出于好奇,你最终是如何解决这个问题的?@SwiftArchitect我自己还没有遇到过这个特定的场景,但既然Rupert说我包含的代码片段有效,我可能会同意。当然,在答案下面发表了评论!我将删除我愚蠢的问题,并且很快就删除这个评论。。。