代码之家  ›  专栏  ›  技术社区  ›  Ashutosh

使用uiimage滚动uiscrollview

  •  0
  • Ashutosh  · 技术社区  · 7 年前

    我的应用程序中有一个水平的uiscrollview,从它开始有一个非常长的uiimageview。我有一个定时器和动画来创建一个假象,在滚动视图下的图像是自动滚动的。一旦图像结束,我会动态地将类似的图像添加到滚动视图中,使其看起来像是重复的图像本身。

    这就是我希望它们在滚动视图下显示的方式:image1 image2 image3 image4……这些图像将从右向左滚动。在你登录之前,它是如何在Behance的iPhone应用程序中工作的。

    这是我拥有的代码(在故事板中,我已经添加了滚动视图和一个uiImageView)。

    override func viewDidAppear(_ animated: Bool) {
    
            Timer.scheduledTimer(timeInterval: 0.6, target: self, selector: #selector(scrollImage), userInfo: nil, repeats: true)
        }
    
        @objc func scrollImage() {
            offSet.x = offSet.x + CGFloat(20)
            UIView.animate(withDuration: 1.0, animations: {
                self.behanceView.setContentOffset(self.offSet, animated: false)
            })
        }
    
         func addImagetoScrollView() {
            let imageView = UIImageView(image:UIImage(named:"Landing_Scrollable"))
            print(imageCount*Int(self.behanceView.contentSize.width)+100)
            imageView.frame = CGRect(x:imageCount*Int(self.behanceView.contentSize.width), y: 0, width: 875, height: 502)
            self.behanceView.contentSize = CGSize(width: imageView.bounds.size.width * CGFloat(imageCount), height: imageView.bounds.size.height)
            self.behanceView.addSubview(imageView)
            imageCount+=1
        }
    
        extension ViewController: UIScrollViewDelegate {
            func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
                let scrollViewWidth = scrollView.frame.size.width;
                let scrollOffset = scrollView.contentOffset.x;
                print(imageCount*Int(self.behanceView.contentSize.width - scrollViewWidth))
                if scrollOffset >= CGFloat(imageCount*Int(self.behanceView.contentSize.width - scrollViewWidth)) {
                    self.addImagetoScrollView()
                }
            }
        }
    

    但当我看到它在运行时,它会做一些事情,动画也会停止。

    有人能帮忙吗?

    谢谢,

    1 回复  |  直到 7 年前
        1
  •  2
  •   rob mayoff    7 年前

    我从来没有见过Behance应用程序,但我猜你在问如何在屏幕上无限期地显示无缝平铺的背景图像,比如:

    ( pattern image by evan eckard. )

    我在演示中使用了1秒的动画持续时间,但您可能希望在真正的应用程序中使用更长的持续时间。

    你不应该用计时器。核心动画可以为您执行动画,并让它执行动画更平滑和更高效。(您可能认为核心动画正在执行您的动画,因为您使用的是 uiview animation,但我相信动画滚动视图的 contentoffset does not use core animation because the scroll view has to call its delegate's scrollviewdidsroll在每个动画步骤上。

    您也不应该为此使用滚动视图。 uiscrollview exists to allow the user to scroll.由于不允许用户滚动,因此不应使用滚动视图。

    以下是设置背景的方法:

    1. 创建 two 相同的图像视图(编号为0和1),显示相同的图像。确保每个图像视图都足够大,足以填满屏幕。

    2. 将图像视图0的左边缘放在根视图的左边缘。将图像视图1的左边缘置于图像视图0的右边缘。由于每个图像视图的大小足以填满屏幕,因此图像视图1将完全从屏幕的右边缘开始。

    3. 动画图像视图0的 transform.translation.x from 0 to -image view.bounds.size.width 。这将使它精确地按自己的宽度向左滑动,因此当动画到达其末端时,图像视图0的右边缘位于屏幕的左边缘(因此图像视图0完全离开屏幕的左边缘)。将动画的 repeatcount 设置为 .infinity

    4. 将相同的动画添加到图像视图1。因此,图像视图1在图像视图0离开时出现在屏幕上,正好覆盖了图像视图0动画显示的像素。

      1. 两个动画同时结束。当它们结束时,图像视图1正好是图像视图0的起始位置。由于两个动画都设置为无限重复,因此它们都会立即重新开始。当图像视图0的动画重新开始时,图像视图0立即跳回到其开始位置,即图像视图1结束的位置。因为两个图像视图都显示相同的图像,所以屏幕上的像素不会改变。这使得动画循环无缝。

        这是我的代码:

        导入uikit 类ViewController:uiViewController{ 重写func viewdidload()。{ super.viewdidload()。 对于ImageView中的ImageView{ imageView.image=模式图像 imageView.contentMode=.scaleToFill View.AddSubView(图像视图) } } 重写func viewDidLayoutSubviews()。{ super.viewdidlayoutSubviews()。 Let Bounds=视图边界 让patternSize=patternImage.size //如有必要,放大图像,使其至少与两个轴上的屏幕一样大。 //但请确保比例至少为1,这样如果图像大于屏幕,我就不会缩小图像。 设为scale=max(1为cgfloat,bounds.size.width/patternsize.width,bounds.size.height/patternsize.height) 让imageframe=cgrct(x:0,y:0,width:scale*patternsize.width,height:scale*patternsize.height) 在ImageView.Enumerated()中的(i,ImageView){ imageview.frame=imageframe.offsetby(dx:cgfloat(i)*imageframe.size.width,dy:0) 让animation=cabasicanimation(keypath:“transform.translation.x”)。 动画.fromValue=0 animation.toValue=-imageframe.size.width 动画。持续时间=1 animation.repeatcount=.infinity animation.timingFunction=camereditingFunction(名称:.linear) //下一行防止iOS在应用程序进入后台时删除动画。 animation.isremovedOnCompletion=false imageview.layer.add(动画,forkey:animation.keypath) } } private let imageview:[uiimageview]=[.init(),.init()] private let patternimage=imageliteral(resourcename:“pattern”)。 }
        无限期地显示,如:

        demo

        (Pattern image by Evan Eckard.)

        我在演示中使用了1秒的动画持续时间,但是你可能想要一个真正的应用程序更长的持续时间。

        你不应该用计时器。核心动画可以为您执行动画,并让它执行动画更平滑和更高效。(您可能认为核心动画正在执行您的动画,因为您正在使用UIView动画,但我相信动画滚动视图的contentOffset使用核心动画,因为滚动视图必须调用其代理的scrollViewDidScroll在每个动画步骤中。)

        您也不应该为此使用滚动视图。UIScrollView存在以允许用户滚动。既然你不让用户滚动,你就不应该使用ui滚动视图.

        以下是设置背景的方法:

        1. 创建相同的图像视图(编号为0和1),显示相同的图像。确保图像视图的大小足以填满屏幕。

        2. 将图像视图0的左边缘放在根视图的左边缘。将图像视图1的左边缘置于图像视图0的右边缘。由于每个图像视图的大小足以填满屏幕,因此图像视图1将完全从屏幕的右边缘开始。

        3. 动画图像视图0的transform.translation.x从0到-imageView.bounds.size.width.这将使它精确地按自己的宽度向左滑动,因此当动画到达其末端时,图像视图0的右边缘位于屏幕的左边缘(因此图像视图0完全离开屏幕的左边缘)。设置动画的repeatCount.infinity.

        4. 将相同的动画添加到图像视图1。因此,当图像视图0离开时,图像视图1进入屏幕,正好覆盖图像视图0动画显示的像素。

        两个动画同时结束。当它们结束时,图像视图1正好是图像视图0的起始位置。由于两个动画都设置为无限重复,因此它们都会立即重新开始。当图像视图0的动画重新开始时,图像视图0立即跳回到其开始位置,即图像视图1结束的位置。因为两个图像视图都显示相同的图像,所以屏幕上的像素不会改变。这使得动画循环无缝。

        这是我的代码:

        import UIKit
        
        class ViewController: UIViewController {
        
            override func viewDidLoad() {
                super.viewDidLoad()
        
                for imageView in imageViews {
                    imageView.image = patternImage
                    imageView.contentMode = .scaleToFill
                    view.addSubview(imageView)
                }
            }
        
            override func viewDidLayoutSubviews() {
                super.viewDidLayoutSubviews()
        
                let bounds = view.bounds
        
                let patternSize = patternImage.size
                // Scale the image up if necessary to be at least as big as the screen on both axes.
                // But make sure scale is at least 1 so I don't shrink the image if it's larger than the screen.
                let scale = max(1 as CGFloat, bounds.size.width / patternSize.width, bounds.size.height / patternSize.height)
                let imageFrame = CGRect(x: 0, y: 0, width: scale * patternSize.width, height: scale * patternSize.height)
        
                for (i, imageView) in imageViews.enumerated() {
                    imageView.frame = imageFrame.offsetBy(dx: CGFloat(i) * imageFrame.size.width, dy: 0)
        
                    let animation = CABasicAnimation(keyPath: "transform.translation.x")
                    animation.fromValue = 0
                    animation.toValue = -imageFrame.size.width
                    animation.duration = 1
                    animation.repeatCount = .infinity
                    animation.timingFunction = CAMediaTimingFunction(name: .linear)
        
                    // The following line prevents iOS from removing the animation when the app goes to the background.
                    animation.isRemovedOnCompletion = false
        
                    imageView.layer.add(animation, forKey: animation.keyPath)
                }
            }
        
            private let imageViews: [UIImageView] = [.init(), .init()]
            private let patternImage = #imageLiteral(resourceName: "pattern")
        
        }