Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.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 无法在另一个UIScrollView内的UIScrollView中检测到点击_Ios_Swift_Uiscrollview_Uikit - Fatal编程技术网

Ios 无法在另一个UIScrollView内的UIScrollView中检测到点击

Ios 无法在另一个UIScrollView内的UIScrollView中检测到点击,ios,swift,uiscrollview,uikit,Ios,Swift,Uiscrollview,Uikit,我有一个垂直滚动的UIScrollView,它跨越了整个ViewController,其中包含这个ContentView(UIView),因此我能够检测滚动视图边界之外的触摸事件: import UIKit class ContentView: UIView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let reversedSubviews = subv

我有一个垂直滚动的
UIScrollView
,它跨越了整个
ViewController
,其中包含这个
ContentView
UIView
),因此我能够检测滚动视图边界之外的触摸事件:

import UIKit

class ContentView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let reversedSubviews = subviews.reversed()
        let hitSubview = reversedSubviews
            .first(where: { $0.hitTest(convert(point, to: $0), with: event) != nil })
        if hitSubview != nil {
            return hitSubview
        }
        return super.hitTest(point, with: event)
    }
}
这就是等级制度的观点

UIScrollView (vertical scroll) //Works
|
 -- ContentView(UIView)
    |
    --UIScrollView (horizontal scroll) //Works
       |
       -- UIView
          |
          --UIButton //This does not work
    |
    --UIScrollView (horizontal scroll) //Works
       |
       -- UIView
          |
          --UIButton //This does not work
在这个
ContentView
中,我还有几个其他的水平滚动
UIScrollView
。但由于
ContentView
,我无法检测这些滚动视图中的触摸事件

我应该如何处理这个问题,以便能够在所有滚动视图中检测到触摸事件,即使子视图超出范围


ContentView
放在水平滚动视图中是没有帮助的。

当我对
UITableView
&
UICollectionView
以及如何避免在滚动方向相同(水平和水平或垂直和垂直)的情况下嵌套两个滚动视图时,我也遇到了这个问题

当您的内部UI元素在任何屏幕视图的可用视图端口(屏幕上呈现的帧)之外绘制时,通常会发生此问题。有时,这是由于设置了约束的问题造成的

如何调试? 要快速调试,请识别没有响应的按钮的父视图。从
身份检查器
中选中
剪辑到边界
,默认为
。Which
Clips to Bounds
true,您只看到可以与之交互的视图

您可以在以下YouTube视频中查看该问题:

解决方案:
  • 重新查看父视图的约束或结构件计算
  • 如果您不遵循这一点,则另一个
    UICollectionView
    UITableView
    (垂直滚动)中的
    UICollectionView
    (水平滚动)可能是一个很好的方法

  • 这里有一个非常基本的例子

    遵循您的层次结构:

      Main View
      |
      -- UIScrollView (vertical scroll) - Red
        |
         -- ContentView(UIView) - Medium Blue
            |
            -- UIScrollView (horizontal scroll) - Green
               |
               -- UIView - Light Gray
                  |
                  -- UIButton - Blue
               |
               -- UIView - Light Gray
                  |
                  -- UIButton - Blue
            |
            -- UIScrollView (horizontal scroll) - Green
               |
               -- UIView - Light Gray
                  |
                  -- UIButton - Blue
               |
               -- UIView - Light Gray
                  |
                  -- UIButton - Blue
            |
    
    这是它的外观-可以点击按钮:

    向下滚动并向右滚动每个水平滚动视图后:

    示例代码。。。无需
    @IBOutlet
    @IBAction
    连接,只需将视图控制器的类分配给
    MultiCrollViewController

    class MultiScrollViewController: UIViewController {
        
        let vertScrollView = UIScrollView()
        
        let contentView = UIView()
        
        let hScrollA = UIScrollView()
        let hScrollB = UIScrollView()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            [vertScrollView, contentView, hScrollA, hScrollB].forEach {
                $0.translatesAutoresizingMaskIntoConstraints = false
            }
            
            contentView.addSubview(hScrollA)
            contentView.addSubview(hScrollB)
            
            vertScrollView.addSubview(contentView)
            
            view.addSubview(vertScrollView)
            
            let g = view.safeAreaLayoutGuide
            let svContentG = vertScrollView.contentLayoutGuide
            let svFrameG = vertScrollView.frameLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // vertical scroll view with 20-pts on each side for "padding"
                vertScrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
                vertScrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                vertScrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
                vertScrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
                
                // content view Top / Leading / Bottom 12-pts to content layout guide
                contentView.topAnchor.constraint(equalTo: svContentG.topAnchor, constant: 12.0),
                contentView.leadingAnchor.constraint(equalTo: svContentG.leadingAnchor, constant: 12.0),
                contentView.bottomAnchor.constraint(equalTo: svContentG.bottomAnchor, constant: -12.0),
                // content view Trailing to content layout guide
                contentView.trailingAnchor.constraint(equalTo: svContentG.trailingAnchor, constant: 0.0),
                
                // content view Width: scroll frame width minus 24-pts (we don't want horizontal scrolling)
                contentView.widthAnchor.constraint(equalTo: svFrameG.widthAnchor, constant: -24.0),
                
                // horizontal scroll view A Top / Leading / Trailing 8-pts to contentView
                hScrollA.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8.0),
                hScrollA.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
                hScrollA.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0),
                
                // horizontal scroll view B Top 20-pts from Bottom of hScrollA
                hScrollB.topAnchor.constraint(equalTo: hScrollA.bottomAnchor, constant: 20.0),
                
                // horizontal scroll view B Leading / Trailing / Bottom 8-pts to contentView
                hScrollB.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
                hScrollB.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0),
                hScrollB.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8.0),
                
                // so we have some vertical scrolling, make each horizontal scroll view
                //  60% the height of the vertical scroll view frame
                hScrollA.heightAnchor.constraint(equalTo: svFrameG.heightAnchor, multiplier: 0.6),
                hScrollB.heightAnchor.constraint(equalTo: hScrollA.heightAnchor),
                
            ])
            
            // each horizontal scroll view will have
            //  two UIViews, each with a UIButton
            
            let btn1inA = UIButton()
            let btn2inA = UIButton()
            
            let btn1inB = UIButton()
            let btn2inB = UIButton()
            
            let btn1inAView = UIView()
            let btn2inAView = UIView()
            
            let btn1inBView = UIView()
            let btn2inBView = UIView()
            
            let btnViews = [btn1inAView, btn2inAView, btn1inBView, btn2inBView]
            
            let btns = [btn1inA, btn2inA, btn1inB, btn2inB]
            let ttls = ["Button 1 in A", "Button 2 in A", "Button 1 in B", "Button 2 in B"]
            
            for (btn, str) in zip(btns, ttls) {
                btn.setTitle(str, for: [])
                btn.setTitleColor(.white, for: .normal)
                btn.setTitleColor(.gray, for: .highlighted)
                btn.titleLabel?.font = .boldSystemFont(ofSize: 18)
                btn.backgroundColor = .blue
                btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
                btn.translatesAutoresizingMaskIntoConstraints = false
                btn.addTarget(self, action: #selector(self.btnTap(_:)), for: .touchUpInside)
            }
            
            for (btn, v) in zip(btns, btnViews) {
                v.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
                v.translatesAutoresizingMaskIntoConstraints = false
                v.addSubview(btn)
                // center each button in a view with 8-pts padding on all 4 sides
                NSLayoutConstraint.activate([
                    btn.topAnchor.constraint(equalTo: v.topAnchor, constant: 8.0),
                    btn.leadingAnchor.constraint(equalTo: v.leadingAnchor, constant: 8.0),
                    btn.trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -8.0),
                    btn.bottomAnchor.constraint(equalTo: v.bottomAnchor, constant: -8.0),
                ])
            }
            
            // add button-holding-views to horizontal scroll views
            hScrollA.addSubview(btn1inAView)
            hScrollA.addSubview(btn2inAView)
            
            hScrollB.addSubview(btn1inBView)
            hScrollB.addSubview(btn2inBView)
            
            let svAContentG = hScrollA.contentLayoutGuide
            let svAFrameG = hScrollA.frameLayoutGuide
            
            let svBContentG = hScrollB.contentLayoutGuide
            let svBFrameG = hScrollB.frameLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // button 1 in hScroll A
                //  top == content top + 20
                btn1inAView.topAnchor.constraint(equalTo: svAContentG.topAnchor, constant: 20.0),
                //  leading == content leading + 20
                btn1inAView.leadingAnchor.constraint(equalTo: svAContentG.leadingAnchor, constant: 20.0),
                
                // button 2 in hScroll A
                //  leading == button 1 leading + 600 (so we get horizontal scrolling
                btn2inAView.leadingAnchor.constraint(equalTo: btn1inAView.trailingAnchor, constant: 600.0),
                
                //  trailing == content trailing - 20
                btn2inAView.trailingAnchor.constraint(equalTo: svAContentG.trailingAnchor, constant: -20.0),
                
                //  bottom to content bottom
                btn2inAView.bottomAnchor.constraint(equalTo: svAContentG.bottomAnchor),
                
                //  bottom 20-pts from hScroll A frame bottom (so it's at lower-right)
                btn2inAView.bottomAnchor.constraint(equalTo: svAFrameG.bottomAnchor, constant: -20.0),
                
                // button 1 in hScroll B
                //  top == content top + 20
                btn1inBView.topAnchor.constraint(equalTo: svBContentG.topAnchor, constant: 20.0),
                
                //  leading == content leading + 20
                btn1inBView.leadingAnchor.constraint(equalTo: svBContentG.leadingAnchor, constant: 20.0),
                
                // button 2 in hScroll A
                //  leading == button 1 leading + 600 (so we get horizontal scrolling
                btn2inBView.leadingAnchor.constraint(equalTo: btn1inBView.trailingAnchor, constant: 600.0),
                
                //  trailing == content trailing - 20
                btn2inBView.trailingAnchor.constraint(equalTo: svBContentG.trailingAnchor, constant: -20.0),
                
                //  bottom to content bottom
                btn2inBView.bottomAnchor.constraint(equalTo: svBContentG.bottomAnchor),
                
                //  bottom 20-pts from hScroll B frame bottom (so it's at lower-right)
                btn2inBView.bottomAnchor.constraint(equalTo: svBFrameG.bottomAnchor, constant: -20.0),
                
            ])
            
            // some background colors so we can see the frames
            view.backgroundColor = .yellow
            vertScrollView.backgroundColor = .red
            
            // medium blue
            contentView.backgroundColor = UIColor(red: 0.0, green: 0.5, blue: 1.0, alpha: 1.0)
            
            hScrollA.backgroundColor = .green
            hScrollB.backgroundColor = .green
            
        }
        
        @objc func btnTap(_ sender: UIButton) -> Void {
            print(sender.currentTitle ?? "No Button Title")
        }
        
    }
    

    从布局的描述中,不清楚为什么要使用
    hitTest()
    ?如果您将视图/按钮放置在
    contentView
    范围之外,则可能没有正确操作(除非您能够说明/描述您需要执行的原因)。我实现了您的代码,它工作得非常完美,让我意识到故事板中的问题是什么。这是一个简单的修复。我从ContentView中删除了hitTest方法,并确保每个ScrollView的ContentView都覆盖了它的所有子视图。换句话说,我将bottomAnchor.containt添加到垂直scrollview的底部子视图中。并将trailingAnchor.constraint拖至水平滚动视图的最右侧子视图。我会接受你的回答。谢谢你抽出时间。