简体   繁体   English

使用 Lottie 自定义 UIRefreshControl

[英]Custom UIRefreshControl with Lottie

My goal is to replace the default spinner of the UIRefreshControl with a Lottie animation.我的目标是用 Lottie 动画替换UIRefreshControl的默认微调器。

My issue is that the animation does not play immediately when I pull down my UICollectionView whose subview is the UIRefreshControl .我的问题是当我拉下我的UICollectionView时动画不会立即播放,其子视图是UIRefreshControl The animation only plays when I scroll down slightly and pause my finger.动画仅在我稍微向下滚动并暂停手指时播放。 The moment I again start moving the scrolling position it immediately goes back to its initial starting state not playing.我再次开始移动滚动位置的那一刻,它立即回到不播放的初始状态。

Any guidance would be appreciated, below is relevant code..任何指导将不胜感激,以下是相关代码..

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
        }
    }
}

You don't see the animation playing while you are scrolling because every time scrollViewDidScroll is called you restart the animation by calling play .您在滚动时看不到动画播放,因为每次调用scrollViewDidScroll时,您都会通过调用play重新启动动画。 And because that function is called almost constantly while you scroll the animation does not have a chance to play more than its first frame.并且因为在滚动动画时几乎不断调用该函数,所以没有机会播放超过其第一帧的内容。 So it looks paused.所以它看起来暂停了。

When implementing a custom Refresh Control you have to implement 3 phases:实现自定义刷新控件时,您必须实现 3 个阶段:

1. User scrolls but the refresh has not been triggered yet 1.用户滚动但尚未触发刷新

In this phase you probably want to show a progress in your animation depending on how far the user has scrolled.在此阶段,您可能希望根据用户滚动的距离显示动画进度。 To do this you calculate the progress in scrollViewDidScroll and pass it to the LOTAnimationView 's animationProgress property.为此,您在scrollViewDidScroll计算进度并将其传递给LOTAnimationViewanimationProgress属性。

To calculate this progress you have to know how far the user has to scroll down until the refresh is triggered.要计算此进度,您必须知道用户必须向下滚动多远才能触发刷新。 In my experience this happens at a contentOffset.y of approximately 150 .根据我的经验,这发生在contentOffset.y大约150

2. Refresh is triggered 2.刷新被触发

When the user has scrolled down enough a .valueChanged ControlEvent is triggered.当用户向下滚动足够.valueChanged会触发.valueChanged ControlEvent。 When this happens you start the looping animation by calling play() on the LOTAnimationView发生这种情况时,您可以通过在LOTAnimationView上调用play()来启动循环动画

3. Refresh is done 3.刷新完成

When the refreshing is completed you call endRefreshing() on your custom Refresh Control.刷新完成后,您可以在自定义刷新控件上调用endRefreshing() When this happens you stop the animation by calling stop() on the LOTAnimationView发生这种情况时,您可以通过在LOTAnimationView上调用stop()来停止动画

Check out this small example of a LottieRefreshControl that I use in one of my projects:查看我在我的一个项目中使用的 LottieRefreshControl 的这个小例子:

import UIKit
import Lottie

class LottieRefreshControl: UIRefreshControl {
fileprivate let animationView = Lottie.AnimationView(name: "searchAnimation")
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.currentProgress = progress
}

override func beginRefreshing() {
    super.beginRefreshing()
    isAnimating = true
    animationView.currentProgress = 0
    animationView.play()
}

override func endRefreshing() {
    super.endRefreshing()
    animationView.stop()
    isAnimating = false
}
}

private extension LottieRefreshControl {
func setupView() {
    // hide default indicator view
    tintColor = .clear
    animationView.loopMode = .loop
    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)
    ])
}
}

Now you only have to call updateProgress on the Refresh Control from scrollViewDidScroll :现在,您只需从scrollViewDidScroll调用 Refresh Control 上的updateProgress

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    refreshControl.updateProgress(with: scrollView.contentOffset.y)
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM