如何获取 uiscrollView 位于 scrollIndicator 的元素
How to get the element of uiscrollView which is at scrollIndicator
我想在用户滚动时获取它在 scrollIndicator 中的元素。
因此,更清楚地说,当用户滚动时,我想获取正在拖动的元素(在 scoll 指示器处)。
我的滚动视图是水平的。
提前致谢
如果您想在用户开始拖动某物时获取位置,您可以通过以下方式实现 willBeginDragging
。
extension ViewController : UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
let location = scrollView.panGestureRecognizer.location(in: scrollView)
print(location)
}
}
根据您的描述,您所有的 scrollView 子视图都将具有相同的大小,并且每个都是 scrollView 框架的大小。
使用该假设,基本思路是获取 scrollView 的 contentOffset
,将其除以 scrollView 的宽度,然后将其转换为 Int
得到 "index" 显示其中的子视图。
因此,如果您的 scrollView 是 100 磅宽,则您添加的每个图像视图都将是 100 磅宽。如果用户已经滚动,所以 contentOffset
是 20
(向左滚动一点),索引将是:
Int(20.0 / 100.0) // equals 0
如果用户刚刚滚动到第三张图片的末尾,contentOffset
将为(例如)315
,索引将为:
Int(315.0 / 100.0) // equals 3
(当然使用标准的基于零的索引)
这是一个 基本 示例 - 所有元素都添加到代码中,因此只需在 Storyboard 中使用空 ViewController 并将其分配给此 class:
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)
}
}
请记住 --- 如果用户向左滚动直到在左边缘只能看到图像的单个像素宽度,该图像 仍将被视为 "visible image view"。
您可能希望将索引计算更改为 return "most visible" 子视图,您可以这样做:
return Int((offX / svW).rounded())
或者可能仅当下一个图像视图至少有 75% 可见时...满足您的需要。
我想在用户滚动时获取它在 scrollIndicator 中的元素。 因此,更清楚地说,当用户滚动时,我想获取正在拖动的元素(在 scoll 指示器处)。
我的滚动视图是水平的。
提前致谢
如果您想在用户开始拖动某物时获取位置,您可以通过以下方式实现 willBeginDragging
。
extension ViewController : UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
let location = scrollView.panGestureRecognizer.location(in: scrollView)
print(location)
}
}
根据您的描述,您所有的 scrollView 子视图都将具有相同的大小,并且每个都是 scrollView 框架的大小。
使用该假设,基本思路是获取 scrollView 的 contentOffset
,将其除以 scrollView 的宽度,然后将其转换为 Int
得到 "index" 显示其中的子视图。
因此,如果您的 scrollView 是 100 磅宽,则您添加的每个图像视图都将是 100 磅宽。如果用户已经滚动,所以 contentOffset
是 20
(向左滚动一点),索引将是:
Int(20.0 / 100.0) // equals 0
如果用户刚刚滚动到第三张图片的末尾,contentOffset
将为(例如)315
,索引将为:
Int(315.0 / 100.0) // equals 3
(当然使用标准的基于零的索引)
这是一个 基本 示例 - 所有元素都添加到代码中,因此只需在 Storyboard 中使用空 ViewController 并将其分配给此 class:
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)
}
}
请记住 --- 如果用户向左滚动直到在左边缘只能看到图像的单个像素宽度,该图像 仍将被视为 "visible image view"。
您可能希望将索引计算更改为 return "most visible" 子视图,您可以这样做:
return Int((offX / svW).rounded())
或者可能仅当下一个图像视图至少有 75% 可见时...满足您的需要。