简体   繁体   English

如何将响应者传递给 ScrollView?

[英]How to pass a responder to ScrollView?

My view hierarchy我的视图层次结构

This is the View layer I created.这是我创建的视图层。 I want to transfer all Touch Events that happen in UIView to UIScrollView, but I don't know how.我想将 UIView 中发生的所有触摸事件转移到 UIScrollView,但我不知道如何。 I didn't put it as a SubView of ScrollView because UIView should be lock.我没有把它作为 ScrollView 的子视图,因为 UIView 应该被锁定。 I want to use the default Gesture in UIScrollView for up or down drag (PanGesture) that happens in UIView.我想使用 UIScrollView 中的默认手势进行 UIView 中发生的向上或向下拖动(PanGesture)。 I made a PanGesture in the ViewController using ResponderChain to respond, but when it is Touch State.Ended like ScrollView I couldn't implement a scroll that ends smoothly.我在 ViewController 中使用 ResponderChain 进行了 PanGesture 响应,但是当它是 Touch State.Ended 时,我无法实现平滑结束的滚动。 Any way to solve this problem?有什么办法可以解决这个问题? Thank you for your reply.感谢你的回复。

One approach that may work for you...一种可能对您有用的方法...

Use a UIView subclass for your "stationary pink view" and implement hitTest :使用UIView子类作为“固定粉色视图”并实现hitTest

class MyParentView: UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let hitView = super.hitTest(point, with: event)
        if hitView == self {
            return nil
        } else {
            return hitView
        }
    }
}

that will allow the touch/drag to effectively "pass through" to the scroll view underneath, while still allowing user interaction with its own subviews.这将允许触摸/拖动有效地“通过”到下面的滚动视图,同时仍然允许用户与其自己的子视图交互。

Here's an example controller showing it in use:这是一个示例 controller 显示它正在使用中:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(red: 0.61, green: 0.86, blue: 0.93, alpha: 1.0)
        
        let scrollView = UIScrollView()
        scrollView.backgroundColor = UIColor(red: 0.96, green: 0.93, blue: 0.79, alpha: 1.0)
        
        let pinkView = MyParentView()
        pinkView.backgroundColor = UIColor(red: 0.96, green: 0.70, blue: 0.86, alpha: 1.0)
    
        // a button and label to add to the pink view
        let btn = UIButton()
        btn.setTitle("Some Button", for: [])
        btn.setTitleColor(.white, for: .normal)
        btn.setTitleColor(.lightGray, for: .highlighted)
        btn.backgroundColor = .systemRed
        btn.layer.cornerRadius = 8
        btn.translatesAutoresizingMaskIntoConstraints = false

        let label = UILabel()
        label.text = "Some Label"

        [btn, label].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            pinkView.addSubview(v)
        }

        // a vertical stack view with a bunch of labels
        //  to use as the scroll content
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 40.0
        for i in 1...30 {
            let l = UILabel()
            l.text = "Label \(i)"
            stack.addArrangedSubview(l)
        }

        // add stack view to scroll view
        stack.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(stack)
        
        // add scroll view to view
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)

        // add pink view ot view
        pinkView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(pinkView)

        let g = view.safeAreaLayoutGuide
        let cg = scrollView.contentLayoutGuide
        let fg = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain scroll view to all 4 sides with 20-points "padding"
            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),

            // constrain stack view to all 4 sides of scroll view's Content Layout Guide
            //  with 20-points "padding"
            stack.topAnchor.constraint(equalTo: cg.topAnchor, constant: 20.0),
            stack.leadingAnchor.constraint(equalTo: cg.leadingAnchor, constant: 20.0),
            stack.trailingAnchor.constraint(equalTo: cg.trailingAnchor, constant: -20.0),
            stack.bottomAnchor.constraint(equalTo: cg.bottomAnchor, constant: -20.0),
            // stack view width is scroll view's Content Layout Guide width
            //  minus 40-points (20-points on each side)
            stack.widthAnchor.constraint(equalTo: fg.widthAnchor, constant: -40.0),
            
            // constrain pink view relative to scroll view
            //  10-points from top
            //  100-points leading (so we can see the scrolling)
            //  trailing
            //  height of 320-points
            pinkView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10.0),
            pinkView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 100.0),
            pinkView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: 0.0),
            pinkView.heightAnchor.constraint(equalToConstant: 320.0),

            // constrain button and label inside pink view
            btn.topAnchor.constraint(equalTo: pinkView.topAnchor, constant: 40.0),
            btn.leadingAnchor.constraint(equalTo: pinkView.leadingAnchor, constant: 20.0),
            btn.trailingAnchor.constraint(equalTo: pinkView.trailingAnchor, constant: -20.0),
            
            label.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 20.0),
            label.leadingAnchor.constraint(equalTo: pinkView.leadingAnchor, constant: 20.0),
            label.trailingAnchor.constraint(equalTo: pinkView.trailingAnchor, constant: -20.0),
            
        ])
        
        // add an action for the button so we know it can be tapped
        btn.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)

        // a little "styling"
        scrollView.layer.cornerRadius = 16
        pinkView.layer.cornerRadius = 16
    }
    
    @objc func btnTapped(_ sender: Any?) {
        print("Tapped")
    }

}

The result - I inset the "pink view" from the leading edge of the scroll view to make it easy to see the scroll contents scrolling behind it:结果 - 我从滚动视图的前缘插入了“粉红色视图”,以便轻松查看滚动内容在其后面滚动:

在此处输入图像描述

Touching and dragging on the yellow OR the pink will scroll the scrollView as normal.触摸并拖动黄色或粉红色将正常滚动滚动视图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使滚动视图将触摸事件传递给超级视图? - How to make scrollview to pass touch event to the superview? 可可 NSScrollView 不会将 scrollWheel 事件传递给下一个响应者 - cocoa NSScrollView not pass scrollWheel event to next responder 如何在Swift中使用Page Control将图像从ScrollView传递到NewViewController - How to pass images to a NewViewController from ScrollView with Page Control in Swift 查看 interpretKeyEvents:但是将不需要的事件传递到响应者链上? - View interpretKeyEvents: but pass unwanted ones up the responder chain? 如何在 SwiftUI macOS 中制作第一响应者 - How to make first responder in SwiftUI macOS Swift:如何在 NSAlert 中制作 NSTextField 第一响应者 - Swift: How to make NSTextField first responder in NSAlert 如何在Swift中为NSTextView设置第一响应者? - How to set first responder for NSTextView in Swift? Swift如何在所有uiTextfield上辞职第一响应者 - Swift how to resign first responder on all uiTextfield 如何将 InputAccessoryView 中的 TextField 设置为第一响应者 [Swift] - How to set TextField in InputAccessoryView as First Responder [Swift] SwiftUI:如何让 TextField 成为第一响应者? - SwiftUI: How to make TextField become first responder?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM