Пользовательский UIRefreshControl с Лотти
Моя цель - заменить спиннер по умолчанию UIRefreshControl
с анимацией Лотти.
Моя проблема в том, что анимация не воспроизводится сразу, когда я опускаю UICollectionView
чье подвид является UIRefreshControl
, Анимация воспроизводится только тогда, когда я слегка прокручиваю вниз и делаю паузу пальцем. В тот момент, когда я снова начинаю перемещать позицию прокрутки, он сразу возвращается в исходное начальное состояние, не играя.
Любое руководство будет оценено, ниже приведен соответствующий код.
func setupRefreshControl() {
guard let refreshContents = Bundle.main.loadNibNamed("RefreshControlView", owner: self, options: nil), let refreshView = refreshContents[0] as? RefreshControlView else { return }
refreshView.frame = refreshControl.frame
refreshControl.addSubview(refreshView)
refreshControl.tintColor = UIColor.clear
refreshControl.backgroundColor = UIColor.clear
refreshControl.addTarget(self, action: #selector(exampleFunction), for: .valueChanged)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
for subview in refreshControl.subviews {
if let refreshControlView = subview as? RefreshControlView {
refreshControlView.activityIndicatorControl.animationView.setAnimation(named: "lottieJson")
refreshControlView.activityIndicatorControl.animationView.loopAnimation = true
refreshControlView.activityIndicatorControl.animationView.play()
break
} else {
continue
}
}
}
1 ответ
Вы не видите анимацию во время прокрутки, потому что каждый раз scrollViewDidScroll
называется перезапустить анимацию, вызвав play
, И поскольку эта функция вызывается почти постоянно, пока вы прокручиваете анимацию, у вас нет шансов воспроизвести больше, чем ее первый кадр. Так что это выглядит приостановленным.
При реализации пользовательского элемента управления обновлением вы должны реализовать 3 этапа:
1. Пользователь прокручивает, но обновление еще не было запущено
На этом этапе вы, вероятно, захотите показать прогресс в анимации в зависимости от того, как далеко прокрутил пользователь. Для этого вы рассчитываете прогресс в scrollViewDidScroll
и передать его LOTAnimationView
"s animationProgress
имущество.
Чтобы рассчитать этот прогресс, вы должны знать, как далеко пользователь должен прокрутить вниз, пока не сработает обновление. По моему опыту это происходит на contentOffset.y
примерно 150
,
2. Обновление запущено
Когда пользователь прокрутил достаточно вниз .valueChanged
ControlEvent запущен. Когда это происходит, вы запускаете циклическую анимацию, вызывая play()
на LOTAnimationView
3. Обновление сделано
Когда обновление будет завершено, вы звоните endRefreshing()
на ваш собственный контроль обновления. Когда это происходит, вы останавливаете анимацию, вызывая stop()
на LOTAnimationView
Посмотрите на этот небольшой пример LottieRefreshControl, который я использую в одном из моих проектов:
import UIKit
import Lottie
class LottieRefreshControl: UIRefreshControl {
fileprivate let animationView = LOTAnimationView(name: "refresh")
fileprivate var isAnimating = false
fileprivate let maxPullDistance: CGFloat = 150
override init() {
super.init(frame: .zero)
setupView()
setupLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateProgress(with offsetY: CGFloat) {
guard !isAnimating else { return }
let progress = min(abs(offsetY / maxPullDistance), 1)
animationView.animationProgress = progress
}
override func beginRefreshing() {
super.beginRefreshing()
isAnimating = true
animationView.animationProgress = 0
animationView.play()
}
override func endRefreshing() {
super.endRefreshing()
animationView.stop()
isAnimating = false
}
}
private extension LottieRefreshControl {
func setupView() {
// hide default indicator view
tintColor = .clear
animationView.loopAnimation = true
addSubview(animationView)
addTarget(self, action: #selector(beginRefreshing), for: .valueChanged)
}
func setupLayout() {
animationView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
animationView.centerXAnchor.constraint(equalTo: centerXAnchor),
animationView.centerYAnchor.constraint(equalTo: centerYAnchor),
animationView.widthAnchor.constraint(equalToConstant: 50),
animationView.heightAnchor.constraint(equalToConstant: 32)
])
}
}
Теперь вам нужно только позвонить updateProgress
на элементе управления обновлением с scrollViewDidScroll
:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
refreshControl.updateProgress(with: scrollView.contentOffset.y)
}