jjzjj

ios - 如果同时开始动画,则 UIPageViewController 转换会出现错误

coder 2023-09-10 原文

我在使用 UIPageViewController 的应用程序中有一个奇怪的行为。 我的应用程序的布局是一个 PageViewController(类似相机胶卷),底部有一个广告横幅。

横幅的容器开始时是隐藏的,当广告加载时,我用动画设置了 isHidden=false

我的问题是,当横幅进入屏幕时,如果正在进行中,它会中断 UIPageViewController 转换,如本视频所示:

我创建了一个新项目,只需几行就可以很容易地重现错误,您可以在 GITHUB 中查看它:您只需点击“下一步”按钮,直到加载横幅。它也可以通过滑动 PageViewController 来重现,但更难重现。

完整的示例代码是:

class TestViewController: UIViewController,UIPageViewControllerDelegate,UIPageViewControllerDataSource {
    @IBOutlet weak var constraintAdviewHeight: NSLayoutConstraint!
    weak var pageViewController : UIPageViewController?

    @IBOutlet weak var containerAdView: UIView!
    @IBOutlet weak var adView: UIView!
    @IBOutlet weak var containerPager: UIView!

    var currentIndex = 0;
    var clickEnabled = true

    override func viewDidLoad() {
        super.viewDidLoad()
        let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
        pageViewController = pageVC
        pageVC.delegate = self
        pageVC.dataSource = self
        addChildViewController(pageVC)
        pageVC.didMove(toParentViewController: self)
        containerPager.addSubview(pageVC.view)
        pageVC.view.translatesAutoresizingMaskIntoConstraints = true
        pageVC.view.frame = containerPager.bounds
        pushViewControllerForCurrentIndex()
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.containerAdView.isHidden = true

        DispatchQueue.main.asyncAfter(deadline: .now()+4) {
            self.simulateBannerLoad()
        }

    }

    @IBAction func buttonClicked(_ sender: Any) {
        guard clickEnabled else {return}
        currentIndex -= 1;
        pushViewControllerForCurrentIndex()

    }

    @IBAction func button2Clicked(_ sender: Any) {
        guard clickEnabled else {return}
        currentIndex += 1;
        pushViewControllerForCurrentIndex()
    }


    private func simulateBannerLoad(){
        constraintAdviewHeight.constant = 50
        pageViewController?.view.setNeedsLayout()
        UIView.animate(withDuration: 0.3,
                       delay: 0, options: .allowUserInteraction, animations: {
                        self.containerAdView.isHidden = false
                        self.view.layoutIfNeeded()
                        self.pageViewController?.view.layoutIfNeeded()
        })

    }

    //MARK: data source

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        return getViewControllerForIndex(currentIndex+1)
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        return getViewControllerForIndex(currentIndex-1)
    }

    func getViewControllerForIndex(_ index:Int) -> UIViewController? {
        guard (index>=0) else {return nil}
        let vc :UIViewController = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: "pageTest")
        vc.view.backgroundColor = (index % 2 == 0) ? .red : .green
        return vc
    }

    func pushViewControllerForCurrentIndex() {
        guard let vc = getViewControllerForIndex(currentIndex) else {return}
        print("settingViewControllers start")
        clickEnabled = false
        pageViewController?.setViewControllers([vc], direction: .forward, animated: true, completion: { finished in
            print("setViewControllers finished")
            self.clickEnabled = true
        })
    }
}

注意:另一个不需要的效果是当错误发生时最后一个完成 block 没有被调用,所以它使按钮处于禁用状态:

    func pushViewControllerForCurrentIndex() {
        guard let vc = getViewControllerForIndex(currentIndex) else {return}
        print("settingViewControllers start")
        clickEnabled = false
        pageViewController?.setViewControllers([vc], direction: .forward, animated: true, completion: { finished in
            print("setViewControllers finished")
            self.clickEnabled = true
        })
    }

Note2:横幅加载事件是我无法手动控制的。由于用于显示广告的库,它在主线程中随时可能发生的回调。在示例项目中,这是通过 DispatchQueue.main.asyncAfter: 调用

模拟的

我该如何解决?谢谢

最佳答案

怎么了?

布局会中断动画。

如何预防?

在 pageViewController 动画时不改变布局。

加载广告时: 确认pageViewController是否正在动画,如果是,等到动画完成再更新,或者更新

示例:

    private func simulateBannerLoad(){
        if clickEnabled {
            self.constraintAdviewHeight.constant = 50
        } else {
            needUpdateConstraint = true
        }
    }
    var needUpdateConstraint = false
    var clickEnabled = true {
        didSet {
            if clickEnabled && needUpdateConstraint {
                self.constraintAdviewHeight.constant = 50
                needUpdateConstraint = false
            }
        }
    }

关于ios - 如果同时开始动画,则 UIPageViewController 转换会出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46988411/

有关ios - 如果同时开始动画,则 UIPageViewController 转换会出现错误的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  4. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  5. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  6. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  7. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  8. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  9. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  10. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

随机推荐