如何获取位于scrollIndicator的uiscrollView元素

时间:2019-01-22 10:28:17

标签: ios objective-c uiscrollview

我想在用户滚动时在scrollIndicator上获取它的元素。 因此,更清楚地说,当用户滚动时,我要获取被拖动的元素(位于scoll指示器处)。

我的滚动视图是水平的。

提前谢谢

2 个答案:

答案 0 :(得分:1)

如果您想在用户开始拖动某物时获取位置,则可以通过实现willBeginDragging通过以下方式实现。

extension ViewController : UIScrollViewDelegate {
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        let location = scrollView.panGestureRecognizer.location(in: scrollView)
        print(location)
    }
}

答案 1 :(得分:1)

根据您的描述,所有您的scrollView子视图将具有相同的大小,并且每个子视图都将成为scrollView框架的大小。

使用该假设,基本思想是获取scrollView的contentOffset,除以scrollView的宽度,然后将其转换为Int,以获取子视图的“索引”正在显示。

因此,如果您的scrollView宽度为100点,则您添加的每个图像视图的宽度将为100点。如果用户已滚动,则contentOffset20(向左滚动一点),索引将为:

    Int(20.0 / 100.0)  // equals 0

如果用户滚动到第三张图像的末尾,则contentOffset将是315,例如,索引将是:

    Int(315.0 / 100.0)  // equals 3

(当然,使用基于零的标准索引)

这是一个基本示例-代码中添加了所有元素,因此只需在Storyboard中使用空的ViewController并将其分配给该类:

class ScrollIndexViewController: UIViewController, UIScrollViewDelegate {

    var theScrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    // array of colors for imageView backgrounds
    // could be array of images (or image names), for example
    var colors: [UIColor] = [
        .red,
        .green,
        .blue,
        .orange,
        .magenta,
        .yellow,
        .brown,
        .cyan,
        .purple,
    ]

    override func viewDidLoad() {
        super.viewDidLoad()

        // add the scroll view
        view.addSubview(theScrollView)

        // constrain it to the full view
        NSLayoutConstraint.activate([
            theScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0),
            theScrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0.0),
            theScrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0.0),
            theScrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0),
            ])

        // set scroll view delegate to self
        theScrollView.delegate = self

        // var to use when constraining the scrollable subviews
        var prevImageView: UIImageView?

        // for each element in the array
        for cl in colors {

            // create a new image view
            let v = UIImageView()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.backgroundColor = cl

            // add it to the scroll view
            theScrollView.addSubview(v)

            // all added image views get
            //      width = scroll view width
            //      height = scroll view height
            //      top = scroll view top
            NSLayoutConstraint.activate([
                v.widthAnchor.constraint(equalTo: theScrollView.widthAnchor, multiplier: 1.0),
                v.heightAnchor.constraint(equalTo: theScrollView.heightAnchor, multiplier: 1.0),
                v.topAnchor.constraint(equalTo: theScrollView.topAnchor, constant: 0.0),
                ])

            // if this is the first added image view,
            // constrain leading to scroll view leading
            if cl == colors.first {
                NSLayoutConstraint.activate([
                    v.leadingAnchor.constraint(equalTo: theScrollView.leadingAnchor, constant: 0.0),
                    ])
            }

            // if this is the last added image view,
            // constrain trailing to scroll view trailing
            if cl == colors.last {
                NSLayoutConstraint.activate([
                    v.trailingAnchor.constraint(equalTo: theScrollView.trailingAnchor, constant: 0.0),
                    ])
            }

            // if prevImageView is not nil, that means we've added
            // an image view before this one, so,
            // constrain leading to trailing of previous image view
            if let pv = prevImageView {
                NSLayoutConstraint.activate([
                    v.leadingAnchor.constraint(equalTo: pv.trailingAnchor, constant: 0.0),
                    ])
            }

            // set prevImageView to this image view
            prevImageView = v

        }

    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

        // if user scrolled by swiping

        // calculate the "index" of the visible image view
        let idx = getImageIndex(scrollView)
        // do what you want with the index
        print(#function, "Index: \(idx)")

    }

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

        // if user scrolls and stops (i.e. doesn't swipe and lift)
        if !decelerate {
            // calculate the "index" of the visible image view
            let idx = getImageIndex(scrollView)
            // do what you want with the index
            print(#function, "Index: \(idx)")
        }

    }

    func getImageIndex(_ scrollView: UIScrollView) -> Int {

        // get the contentOffset
        let offX = scrollView.contentOffset.x

        // get the width of the scroll view
        // (which is also the width of the image view subviews)
        let svW = scrollView.frame.width

        // return offset.x / image view width as an Int
        return Int(offX / svW)

    }

}

请紧记---如果用户向左滚动直到图像的左边缘只有一个像素宽度可见, 该图像 仍会被认为是“可见图像视图”。

您可能希望更改索引计算以返回“最可见”子视图,您可以执行以下操作:

    return Int((offX / svW).rounded())

或者只有当下一个图像视图至少可见75%...满足您的需要时,