简体   繁体   中英

Can't Tap UIView in Nested ScrollView

I have a vertical UIScrollView, allScrollView , and a horizontal UIScrollView, hourlyScrollView , nested inside the vertical UIScrollView. In each of the scroll views I have 10 other UIViews that will show data. Each of the views are assigned a UITapGestureRecognizer. I'm able to tap the views that are only in the vertical scroll, but none of the views in the nested horizontal scroll do anything when tapped. If anyone can help me it would be greatly appreciated as I've tried a lot of suggestions on here with no luck.

my view hierarchy:

-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()
    }

create horizontal scroll content

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
    }

create vertical scroll content

    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
    }

tapped functions

    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)")
    }

You haven't set all the required constraints on your hourlyContentView so the horizontal scrollView's size is (0,0) and as such it can't be scrolled or tapped. You can use Debug View Hierarchy in Xcode to see this.

The constraints you need to add are:

  • Between your last hourlyUIView 's trailingAnchor and hourlyContentView 's trailing anchor:
...
    previousHour = hourlyUIView
}

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

let borderViewTop = UIView()
let borderViewBottom = UIView()
...
  • Setting your hourlyContentView heightAnchor equal to the hourlyScrollView height anchor:
hourlyContentView.heightAnchor.constraint(equalTo: hourlyScrollView.heightAnchor).isActive = true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM