Исходя из вашего описания, все ваши подпредставления scrollView будут иметь одинаковый размер, и каждый из них будет иметь размер кадра scrollView.
Используя это предположение, основная идея состоит в том, чтобы получить scrollView * 1003.*, разделите его на ширину scrollView и преобразуйте в Int
, чтобы получить «индекс», который показывает подпредставление.
Итак, если ваш scrollView имеет ширину 100 пунктов, каждыйдобавленное изображение будет иметь ширину 100 пунктов.Если пользователь прокручивал, поэтому contentOffset
равен 20
(прокручивается немного влево), индекс будет:
Int(20.0 / 100.0) // equals 0
Если пользователь прокрутил сразу после конца 3-гоimage, contentOffset
будет (например) 315
, а индекс будет:
Int(315.0 / 100.0) // equals 3
(конечно, используя стандартное индексирование на основе нуля)
Вот пример basic - все элементы добавлены в код, поэтому просто используйте пустой ViewController в Storyboard и присвойте ему этот класс:
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% видимый ... все, что соответствует вашим потребностям.