无法在嵌套的 ScrollView 中点击 UIView

Can't Tap UIView in Nested ScrollView

我有一个垂直 UIScrollView,allScrollView,和一个水平 UIScrollView,hourlyScrollView,嵌套在垂直 UIScrollView 中。在每个滚动视图中,我还有 10 个将显示数据的其他 UIView。每个视图都分配了一个 UITapGestureRecognizer。我可以点击仅在垂直滚动中的视图,但嵌套水平滚动中的 none 视图在点击时可以执行任何操作。如果有人能帮助我,我将不胜感激,因为我在这里尝试了很多建议,但都没有成功。

我的视图层次结构:

-allScrollView (vertical)
  -allContentView
    -hourlyScrollView (horizontal)
      -hourlyContentView
        -10 UIViews
    -dailyContentView
      -10 UIViews

viewDidLoad()

    let dailyContentView = UIView()
    let hourlyContentView = UIView()
    let hourlyScrollView = UIScrollView()
    let allContentView = UIView()
    let allScrollView = UIScrollView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        hourlyScrollView.translatesAutoresizingMaskIntoConstraints = false
        hourlyContentView.translatesAutoresizingMaskIntoConstraints = false
        allContentView.translatesAutoresizingMaskIntoConstraints = false
        allScrollView.translatesAutoresizingMaskIntoConstraints = false
        dailyContentView.translatesAutoresizingMaskIntoConstraints = false
        
        layoutHourlyViews()
        layoutDailyViews()
        finishLayout()
    }

创建水平滚动内容

func layoutHourlyViews() {
        for subview in hourlyScrollView.subviews {
            subview.removeFromSuperview()
        }
        for subView in hourlyContentView.subviews {
            subView.removeFromSuperview()
        }
        var previousHour : UIView? = nil
        for count in 1...10 {
                
            let hourlyUIView = UIView()
            hourlyUIView.backgroundColor = .blue
            hourlyUIView.isUserInteractionEnabled = true
            hourlyUIView.tag = count
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hourlyTap(_:)))
            hourlyUIView.addGestureRecognizer(tapGesture)

            let descriptionLabel = UILabel()
            let borderView = UIView()
            let borderViewTop = UIView()
            let borderViewBottom = UIView()
            borderViewTop.backgroundColor = .black
            borderViewBottom.backgroundColor = .black
            borderViewTop.translatesAutoresizingMaskIntoConstraints = false
            borderViewBottom.translatesAutoresizingMaskIntoConstraints = false
            borderView.translatesAutoresizingMaskIntoConstraints = false
            hourlyUIView.translatesAutoresizingMaskIntoConstraints = false
            descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
            descriptionLabel.text = "test"
            borderView.backgroundColor = .black
            
            hourlyUIView.addSubview(borderViewBottom)
            hourlyUIView.addSubview(borderViewTop)
            hourlyUIView.addSubview(descriptionLabel)
            hourlyUIView.addSubview(borderView)
            
        
            borderViewBottom.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
            borderViewBottom.trailingAnchor.constraint(equalTo: hourlyUIView.trailingAnchor).isActive = true
            borderViewBottom.bottomAnchor.constraint(equalTo: hourlyUIView.bottomAnchor).isActive = true
            borderViewBottom.heightAnchor.constraint(equalToConstant: 2).isActive = true
            
            borderViewTop.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
            borderViewTop.trailingAnchor.constraint(equalTo: hourlyUIView.trailingAnchor).isActive = true
            borderViewTop.topAnchor.constraint(equalTo: hourlyUIView.topAnchor).isActive = true
            borderViewTop.heightAnchor.constraint(equalToConstant: 2).isActive = true
        
            hourlyUIView.widthAnchor.constraint(equalToConstant: 160).isActive = true
            hourlyUIView.heightAnchor.constraint(equalToConstant: 240).isActive = true
            
            descriptionLabel.topAnchor.constraint(equalTo: hourlyUIView.topAnchor, constant: 16).isActive = true
            descriptionLabel.centerXAnchor.constraint(equalTo: hourlyUIView.centerXAnchor, constant: 0).isActive = true

            hourlyContentView.addSubview(hourlyUIView)
           
            if previousHour == nil {
                hourlyUIView.topAnchor.constraint(equalTo: hourlyContentView.topAnchor, constant: 0).isActive = true
                hourlyUIView.leadingAnchor.constraint(equalTo: hourlyContentView.leadingAnchor, constant: 2).isActive = true
            }
            else {
                hourlyUIView.topAnchor.constraint(equalTo: hourlyContentView.topAnchor, constant: 0).isActive = true
                hourlyUIView.leadingAnchor.constraint(equalTo: previousHour!.trailingAnchor, constant: 0).isActive = true
                borderView.bottomAnchor.constraint(equalTo: hourlyUIView.bottomAnchor).isActive = true
                borderView.topAnchor.constraint(equalTo: hourlyUIView.topAnchor).isActive = true
                borderView.widthAnchor.constraint(equalToConstant: 2).isActive = true
                borderView.leadingAnchor.constraint(equalTo: hourlyUIView.leadingAnchor).isActive = true
            }

            
            previousHour = hourlyUIView
        }
        
        let borderViewTop = UIView()
        let borderViewBottom = UIView()
        borderViewTop.backgroundColor = .black
        borderViewBottom.backgroundColor = .black
        borderViewTop.translatesAutoresizingMaskIntoConstraints = false
        borderViewBottom.translatesAutoresizingMaskIntoConstraints = false
        
        hourlyScrollView.addSubview(hourlyContentView)

        hourlyContentView.leadingAnchor.constraint(equalTo: hourlyScrollView.leadingAnchor, constant: 0).isActive = true
        hourlyContentView.topAnchor.constraint(equalTo: hourlyScrollView.topAnchor, constant: 0).isActive = true
        hourlyContentView.trailingAnchor.constraint(equalTo: hourlyScrollView.trailingAnchor, constant: 0).isActive = true
        hourlyContentView.bottomAnchor.constraint(equalTo: hourlyScrollView.bottomAnchor, constant: 0).isActive = true
        
        allContentView.addSubview(hourlyScrollView)
        hourlyScrollView.isScrollEnabled = true
        hourlyScrollView.topAnchor.constraint(equalTo: allContentView.topAnchor, constant: 20).isActive = true
        hourlyScrollView.leadingAnchor.constraint(equalTo: allContentView.leadingAnchor, constant: 0).isActive = true
        hourlyScrollView.trailingAnchor.constraint(equalTo: allContentView.trailingAnchor, constant: 0).isActive = true
    }

创建垂直滚动内容

    func layoutDailyViews() {
        for subview in dailyContentView.subviews {
            subview.removeFromSuperview()
        }
        var previousDay : UIView? = nil
        for count in 1...10 {
            let dailyUIView = UIView()
            //dailyUIView.isUserInteractionEnabled = true
            dailyUIView.tag = count
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dailyTap(_:)))
            dailyUIView.addGestureRecognizer(tapGesture)
            //hourlyUIView.frame.size = CGSize(width: 500, height: 50)
            let descriptionLabel = UILabel()
            dailyUIView.translatesAutoresizingMaskIntoConstraints = false
            descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
            descriptionLabel.text = "daily test"

            let borderView = UIView()
            borderView.translatesAutoresizingMaskIntoConstraints = false
            borderView.backgroundColor = .black
            dailyUIView.addSubview(descriptionLabel)
            dailyUIView.addSubview(borderView)
        
            borderView.bottomAnchor.constraint(equalTo: dailyUIView.bottomAnchor).isActive = true
            borderView.heightAnchor.constraint(equalToConstant: 2).isActive = true
            borderView.leadingAnchor.constraint(equalTo: dailyUIView.leadingAnchor).isActive = true
            borderView.trailingAnchor.constraint(equalTo: dailyUIView.trailingAnchor).isActive = true
            dailyUIView.heightAnchor.constraint(equalToConstant: 100).isActive = true
            
            
            
            descriptionLabel.leadingAnchor.constraint(equalTo: dailyUIView.leadingAnchor, constant: 16).isActive = true
            descriptionLabel.centerYAnchor.constraint(equalTo: dailyUIView.centerYAnchor, constant: 0).isActive = true
            
            
            dailyContentView.addSubview(dailyUIView)
            if previousDay == nil {
                dailyUIView.topAnchor.constraint(equalTo: dailyContentView.topAnchor, constant: 0).isActive = true
            }
            else {
                dailyUIView.topAnchor.constraint(equalTo: previousDay!.bottomAnchor, constant: 0).isActive = true
            }
            dailyUIView.widthAnchor.constraint(equalToConstant: view.frame.width - 4).isActive = true
            dailyUIView.centerXAnchor.constraint(equalTo: dailyContentView.centerXAnchor).isActive = true

            previousDay = dailyUIView
        }
    
        allContentView.addSubview(dailyContentView)
    }
    
    func finishLayout() {
        hourlyScrollView.bottomAnchor.constraint(equalTo: dailyContentView.bottomAnchor, constant: 0).isActive = true
        dailyContentView.topAnchor.constraint(equalTo: allContentView.topAnchor, constant: 260).isActive = true
        dailyContentView.centerXAnchor.constraint(equalTo: allContentView.centerXAnchor, constant:  0).isActive = true
        dailyContentView.leadingAnchor.constraint(equalTo: allContentView.leadingAnchor).isActive = true
        dailyContentView.trailingAnchor.constraint(equalTo: allContentView.trailingAnchor, constant: 0).isActive = true
        dailyContentView.bottomAnchor.constraint(equalTo: allContentView.bottomAnchor).isActive = true
        
        allScrollView.addSubview(allContentView)
        allContentView.topAnchor.constraint(equalTo: allScrollView.topAnchor).isActive = true
        allContentView.leadingAnchor.constraint(equalTo: allScrollView.leadingAnchor).isActive = true
        allContentView.trailingAnchor.constraint(equalTo: allScrollView.trailingAnchor).isActive = true
        allContentView.bottomAnchor.constraint(equalTo: allScrollView.bottomAnchor).isActive = true
        allContentView.centerXAnchor.constraint(equalTo: allScrollView.centerXAnchor).isActive = true
        allContentView.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
        allContentView.heightAnchor.constraint(equalToConstant: 1500).isActive = true
        
        view.addSubview(allScrollView)
        allScrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        allScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        allScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        allScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }

点击函数

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        hourlyScrollView.contentSize = CGSize(width:160 * 10 + 2, height:240)
        allScrollView.contentSize = CGSize(width: view.frame.width, height:1500)
    }
    
    @objc func hourlyTap(_ sender: UITapGestureRecognizer) {
        let tappedView = sender.view
        print("hourly: \(tappedView!.tag)")
    }
    
    @objc func dailyTap(_ sender: UITapGestureRecognizer) {
        let tappedView = sender.view
        print("daily: \(tappedView!.tag)")
    }

您尚未在 hourlyContentView 上设置所有必需的约束,因此水平滚动视图的大小为 (0,0),因此无法滚动或点击。您可以在 Xcode 中使用 Debug View Hierarchy 来查看此内容。

您需要添加的约束是:

  • 在你最后一个 hourlyUIView 的 trailingAnchor 和 hourlyContentView 的尾随锚点之间:
...
    previousHour = hourlyUIView
}

previousHour?.trailingAnchor.constraint(equalTo: hourlyContentView.trailingAnchor).isActive = true

let borderViewTop = UIView()
let borderViewBottom = UIView()
...
  • 将您的 hourlyContentView heightAnchor 设置为等于 hourlyScrollView 高度锚点:
hourlyContentView.heightAnchor.constraint(equalTo: hourlyScrollView.heightAnchor).isActive = true