Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/113.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UIM图像之间的立方体转换_Ios_Swift_Uiimage - Fatal编程技术网

Ios UIM图像之间的立方体转换

Ios UIM图像之间的立方体转换,ios,swift,uiimage,Ios,Swift,Uiimage,我想创建一个视图,当水平滚动时,该视图在具有立方体动画效果的UIImage对象数组之间转换。例如: 有人能给我指出正确的方向,告诉我如何在Swift中水平滚动一组带有立方体过渡动画的UIImage对象吗?这太宽泛了,无法解释,但您可以使用此UIViewController: class CubeScrollViewController: UIViewController,UIScrollViewDelegate { var scrollView:UIScrollView? va

我想创建一个视图,当水平滚动时,该视图在具有立方体动画效果的
UIImage
对象数组之间转换。例如:


有人能给我指出正确的方向,告诉我如何在Swift中水平滚动一组带有立方体过渡动画的
UIImage
对象吗?

这太宽泛了,无法解释,但您可以使用此UIViewController:

class CubeScrollViewController: UIViewController,UIScrollViewDelegate {
    var scrollView:UIScrollView?
    var images:[UIImage] = [UIImage]()
    var imageViews:[IntegerLiteralType:UIImageView] = [IntegerLiteralType:UIImageView]()
    var currentIndex = 0
    var scrollOffset:CGFloat = 0.0
    var previousOffset:CGFloat = 0.0
    var suppressScrollEvent:Bool = false
    var add = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        self.images = [UIImage(named: "image1")!,UIImage(named: "image2")!,UIImage(named:"image3")!,UIImage(named: "image4")!]

    }

    override func viewDidLayoutSubviews()
    {
        super.viewDidLayoutSubviews()
        scrollView?.removeFromSuperview()
        scrollView = UIScrollView(frame: self.view.frame)
        scrollView?.autoresizingMask = [.FlexibleWidth,.FlexibleHeight]
        scrollView?.showsHorizontalScrollIndicator = true
        scrollView?.pagingEnabled = true
        scrollView?.directionalLockEnabled = true;
        scrollView?.autoresizesSubviews = false;
        scrollView?.delegate = self
        self.view.addSubview(scrollView!)
        var index = 0
        for image in self.images
        {
            let imageView = UIImageView(frame: self.view.frame)
            imageView.contentMode = .ScaleAspectFill
            imageView.clipsToBounds = true
            imageView.image = image
            imageView.backgroundColor = UIColor.whiteColor()
            self.imageViews[index] = imageView
            index += 1
        }
        var pages = self.images.count
        if self.images.count > 1
        {
            pages += 2
        }
        self.suppressScrollEvent = true
        self.scrollView?.contentSize = CGSize(width: self.view.bounds.size.width * CGFloat(pages), height: self.view.bounds.size.height)
        self.suppressScrollEvent = false
        self.updateContentOffset()
        self.loadUnloadImageViews()
        self.updateLayout()
    }

    func setCurrentImageIndex(currentImageIndex:IntegerLiteralType)
    {
        self.scrollToImageAtIndex(currentImageIndex,animated:true)
    }

    func scrollToImageAtIndex(index:IntegerLiteralType,animated:Bool)
    {
        var offset = index
        if offset > self.images.count
        {
            offset = offset % self.images.count
        }
        offset = max(-1, offset)+1
        scrollView?.setContentOffset(CGPoint(x: self.view.bounds.size.width * CGFloat(offset),y: 0),animated: animated)
    }

    func scrollForward(animated:Bool)
    {
        self.scrollToImageAtIndex(self.currentIndex+1, animated: animated)
    }

    func scrollBack(animated:Bool)
    {
        self.scrollToImageAtIndex(self.currentIndex-1, animated: animated)
    }

    func reloadData()
    {
        for view:UIImageView in self.imageViews.values
        {
            view.removeFromSuperview()
        }
    }

    func reloadImageAtIndex(index:IntegerLiteralType,animated:Bool)
    {
        let image = self.images[index]
        let oldImageView = self.imageViews[index]
        let imageView = UIImageView(frame: self.view.frame)
        imageView.contentMode = .ScaleAspectFill
        imageView.clipsToBounds = true
        imageView.image = image
        imageView.backgroundColor = UIColor.whiteColor()
        let transform = imageView.layer.transform
        let center = imageView.center

        if animated
        {
            let animation = CATransition()
            animation.type = kCATransitionFade
            self.scrollView?.layer.addAnimation(animation, forKey: nil)
        }
        oldImageView!.removeFromSuperview()
        self.scrollView?.addSubview(imageView)
        imageView.layer.transform = transform
        imageView.center = center
    }

    func updateContentOffset()
    {
        var offset = self.scrollOffset
        if self.images.count>1
        {
            offset+=1.0
            while offset<1.0
            {
                offset+=1.0
            }
            while offset>=CGFloat(self.images.count+1)
            {
                offset-=CGFloat(self.images.count)
            }
        }
        self.previousOffset = offset

        self.suppressScrollEvent = true
        self.scrollView?.contentOffset = CGPointMake(self.view.bounds.size.width*offset, 0.0)
        self.suppressScrollEvent = false
    }

    func updateLayout()
    {
        for index in self.imageViews.keys
        {
            let imageView = self.imageViews[index]
            if imageView != nil && imageView!.superview == nil
            {
                imageView?.layer.doubleSided = false
                self.scrollView?.addSubview(imageView!)
                self.add++
            }
            var angle = (self.scrollOffset - CGFloat(index)) * CGFloat(M_PI_2)
            while angle < 0
            {
                angle = angle + CGFloat(M_PI * 2.0)
            }
            while angle > CGFloat(M_PI*2.0)
            {
                angle = angle - CGFloat(M_PI * 2.0)
            }
            var transform = CATransform3DIdentity
            if angle != 0.0
            {
                transform.m34 = -1.0/500;
                transform = CATransform3DTranslate(transform, 0.0, 0.0, -self.view.bounds.size.width / 2.0)
                transform = CATransform3DRotate(transform, -angle, 0, 1, 0)
                transform = CATransform3DTranslate(transform, 0, 0, self.view.bounds.size.width / 2.0)
            }

            imageView?.bounds = self.view.bounds
            imageView?.center = CGPoint(x: self.view.bounds.size.width * 0.5 + self.scrollView!.contentOffset.x, y: self.view.bounds.size.height * 0.5);
            imageView?.layer.transform = transform
        }
    }

    func loadUnloadImageViews()
    {
        var visibleIndices = [IntegerLiteralType]()
        visibleIndices.append(self.currentIndex)
        visibleIndices.append(self.currentIndex + 1)

        if self.currentIndex > 0
        {
            visibleIndices.append(self.currentIndex - 1)
        }
        else
        {
            visibleIndices.append(-1)
        }

        for index in 0...self.images.count
        {
            if !visibleIndices.contains(index)
            {
                let imageView = self.imageViews[index]
                imageView?.removeFromSuperview()
                self.imageViews.removeValueForKey(index)
            }
        }
        for index in visibleIndices
        {
            var imageView:UIImageView? = nil
            if self.imageViews[index] != nil
            {
                imageView = self.imageViews[index]!
            }
            if imageView == nil && self.images.count > 0
            {
                let newIndex = (index + self.images.count) % self.images.count
                let imageView = UIImageView(frame: self.view.frame)
                imageView.contentMode = .ScaleAspectFill
                imageView.clipsToBounds = true
                imageView.backgroundColor = UIColor.whiteColor()
                imageView.image = self.images[newIndex]
                self.imageViews[index] = imageView
            }
        }

    }

    func scrollViewDidScroll(scrollView: UIScrollView) {
        if !self.suppressScrollEvent
        {
            let offset:CGFloat = scrollView.contentOffset.x / self.view.bounds.size.width
            self.scrollOffset += (offset - self.previousOffset)
            while self.scrollOffset < 0.0
            {
                self.scrollOffset += CGFloat(self.images.count)
            }
            while self.scrollOffset >= CGFloat(self.images.count)
            {
                self.scrollOffset -= CGFloat(self.images.count)
            }
            self.previousOffset = offset

            if offset - floor(offset) == 0.0
            {
                self.scrollOffset = round(self.scrollOffset)
            }

            self.currentIndex = max(0, min(self.images.count - 1, IntegerLiteralType(round(self.scrollOffset))))
            self.updateContentOffset()
            self.loadUnloadImageViews()
            self.updateLayout()

        }
    }

    func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
        let nearestIntegralOffset = round(self.scrollOffset)
        if abs(self.scrollOffset - nearestIntegralOffset) > 0.0
        {
            self.scrollToImageAtIndex(self.currentIndex, animated: true)
        }
    }

}
class CubeScrollViewController:UIViewController、UIScrollViewDelegate{
var scrollView:UIScrollView?
变量图像:[UIImage]=[UIImage]()
var imageViews:[IntegerLiteralType:UIImageView]=[IntegerLiteralType:UIImageView]()
var currentIndex=0
变量scrollOffset:CGFloat=0.0
var previousOffset:CGFloat=0.0
var suppressScrollEvent:Bool=false
var add=0
重写func viewDidLoad(){
super.viewDidLoad()
self.images=[UIImage(名为:“image1”)!、UIImage(名为:“image2”)、UIImage(名为:“image3”)、UIImage(名为:“image4”)!]
}
重写func viewdilayoutsubviews()
{
super.viewDidLayoutSubviews()
scrollView?.removeFromSuperview()
scrollView=UIScrollView(框架:self.view.frame)
scrollView?.autoresizingMask=[.FlexibleWidth、.FlexibleHeight]
scrollView?.showsHorizontalScrollIndicator=true
scrollView?.PaginEnabled=true
scrollView?.directionalLockEnabled=true;
scrollView?.AutoResizesSubView=false;
scrollView?.delegate=self
self.view.addSubview(scrollView!)
var指数=0
自我形象中的形象
{
让imageView=UIImageView(框架:self.view.frame)
imageView.contentMode=.ScaleSpectFill
imageView.clipsToBounds=true
imageView.image=image
imageView.backgroundColor=UIColor.whiteColor()
self.imageView[index]=imageView
指数+=1
}
var pages=self.images.count
如果self.images.count>1
{
页数+=2
}
self.suppressScrollEvent=true
self.scrollView?.contentSize=CGSize(宽度:self.view.bounds.size.width*CGFloat(页面),高度:self.view.bounds.size.height)
self.suppressScrollEvent=false
self.updateContentOffset()
self.loadUnloadImageViews()
self.updateLayout()
}
func setCurrentImageIndex(currentImageIndex:IntegerLiteralType)
{
self.ScrollToImageIndex(currentImageIndex,动画:true)
}
func ScrollToImageIndex(索引:IntegerLiteralType,动画:Bool)
{
var偏移=指数
如果偏移>self.images.count
{
偏移量=偏移量%self.images.count
}
偏移量=最大值(-1,偏移量)+1
scrollView?.setContentOffset(CGPoint(x:self.view.bounds.size.width*CGFloat(offset),y:0),动画:动画)
}
func向前滚动(动画:Bool)
{
self.ScrollToImageIndex(self.currentIndex+1,动画:动画)
}
func回滚(动画:Bool)
{
self.scrollToImageIndex(self.currentIndex-1,动画:动画)
}
func重载数据()
{
对于视图:self.imageview.values中的UIImageView
{
view.removeFromSuperview()视图
}
}
func重新加载ImageAtIndex(索引:IntegerLiteralType,动画:Bool)
{
让image=self.images[index]
让oldImageView=self.imageViews[index]
让imageView=UIImageView(框架:self.view.frame)
imageView.contentMode=.ScaleSpectFill
imageView.clipsToBounds=true
imageView.image=image
imageView.backgroundColor=UIColor.whiteColor()
让transform=imageView.layer.transform
让中心=imageView.center
如果动画
{
让动画=CATTransition()
animation.type=kCATransitionFade
self.scrollView?.layer.addAnimation(动画,forKey:nil)
}
oldImageView!.removeFromSuperview()
self.scrollView?.addSubview(图像视图)
imageView.layer.transform=转换
imageView.center=center
}
func updateContentOffset()
{
var offset=self.scrollOffset
如果self.images.count>1
{
偏移量+=1.0
而offset=CGFloat(self.images.count+1)
{
偏移量-=CGFloat(self.images.count)
}
}
self.previousOffset=偏移量
self.suppressScrollEvent=true
self.scrollView?.contentOffset=CGPointMake(self.view.bounds.size.width*offset,0.0)
self.suppressScrollEvent=false
}
func updateLayout()
{
对于self.imageview.keys中的索引
{
让imageView=self.imageViews[索引]
如果imageView!=nil&&imageView!.superview==nil
{
imageView?.layer.doubleside=false
self.scrollView?.addSubview(imageView!)
自我添加++
}
变量角度=(self.scrollOffset-CGFloat(索引))*CGFloat(M_PI_2)
当角度<0时
{
角度=角度+CGFloat(M_PI*2.0)
}
当角度>CGFloat时(M_PI*2.0)
{
角度=角度-CGFloat(M_PI*2.0)
}
var transform=CATTransferM3DidEntity
如果角度!=0.0
{
transform.m34=-1.0/500;
transform=CATTransformerM3DTTranslate(transform,0.0,0.0,-self.view.bounds.size.width/2.0)
变换=CATTransferM3dRotate(变换,-角度,0,1,0)
transform=CATTransformerM3DTTranslate(transform,0,0,self.view.bounds.size.width/2.0)
}
imageView?.bounds=self.view.bounds
imageView?.center=CGPoint(x:self.view.bounds.size.width*0.5+self.scrollView!.contentOffset.x,y:self.view)。
import UIKit

public class CubeScrollViewController: UIViewController
{
    //MARK: - Properties
    private lazy var scrollView: UIScrollView =
    {
        let scrollView = UIScrollView()
        scrollView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        scrollView.showsHorizontalScrollIndicator = true
        scrollView.isPagingEnabled = true
        scrollView.isDirectionalLockEnabled = true;
        scrollView.autoresizesSubviews = false;
        scrollView.delegate = self
        return scrollView
    }()
    var images = [UIImage]()
    fileprivate var imageViews = [Int: UIImageView]()
    fileprivate var currentIndex = 0
    fileprivate var scrollOffset: CGFloat = 0.0
    fileprivate var previousOffset: CGFloat = 0.0
    fileprivate var suppressScrollEvent = false

    //MARK: - Lifecycle
    override func viewDidLoad()
    {
        super.viewDidLoad()
        self.view.addSubview(self.scrollView)
        for (index, image) in self.images.enumerated()
        {
            let imageView = UIImageView(image: image)
            imageView.contentMode = .scaleAspectFill
            imageView.clipsToBounds = true
            imageView.backgroundColor = UIColor.white
            self.imageViews[index] = imageView
        }
    }

    override func viewDidLayoutSubviews()
    {
        super.viewDidLayoutSubviews()
        self.scrollView.frame = self.view.bounds
        self.imageViews.values.forEach {  $0.frame  = self.view.bounds }
        var pages = CGFloat(self.images.count)
        pages = self.images.count > 1 ? pages + 2 : pages
        self.suppressScrollEvent = true
        self.scrollView.contentSize = CGSize(width: self.view.bounds.width * pages, height: self.view.bounds.height)
        self.suppressScrollEvent = false
        self.updateContentOffset()
        self.loadUnloadViews()
        self.updateLayout()
    }


    //MARK: - Exposed Functions
    func set(_ currentImageIndex: Int)
    {
        self.scrollToImage(at: currentIndex)
    }

    func scrollToImage(at index: Int, animated: Bool = true)
    {
        var offset = index > self.images.count ? index % self.images.count : index
        offset = max(-1, offset) + 1
        self.scrollView.setContentOffset(CGPoint(x: self.view.bounds.width * CGFloat(offset), y: 0.0), animated: animated)
    }

    func scrollForward(animated: Bool = true)
    {
        self.scrollToImage(at: self.currentIndex + 1, animated: animated)
    }

    func scrollBack(animated: Bool = true)
    {
        self.scrollToImage(at: self.currentIndex - 1, animated: animated)
    }

    func reloadData()
    {
        self.imageViews.values.forEach { $0.removeFromSuperview() }
    }

    func reloadImage(at index: Int, animated: Bool = true)
    {
        guard 0 ..< self.images.count ~= index else { return }
        let image = self.images[index]
        let oldImageView = self.imageViews[index]
        let imageView = UIImageView(frame: self.view.bounds)
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.image = image
        imageView.backgroundColor = .white
        let transform = imageView.layer.transform
        let center = imageView.center

        if animated
        {
            let animation = CATransition()
            animation.type = kCATransitionFade
            self.scrollView.layer.add(animation, forKey: nil)
        }
        oldImageView?.removeFromSuperview()
        self.scrollView.addSubview(imageView)
        imageView.layer.transform = transform
        imageView.center = center
    }

    //MARK: - Layout
    fileprivate func updateContentOffset()
    {
        guard self.images.count > 1 else { return }

        var offset = self.scrollOffset
        offset += 1.0
        while offset < 1.0
        {
            offset += 1.0
        }
        while offset >= CGFloat(self.images.count + 1)
        {
            offset -= CGFloat(self.images.count)
        }
        self.previousOffset = offset

        self.suppressScrollEvent = true
        self.scrollView.contentOffset = CGPoint(x: self.view.bounds.width * offset, y: 0.0)
        self.suppressScrollEvent = false

    }

    fileprivate func updateLayout()
    {
        for index in self.imageViews.keys
        {
            guard let imageView = self.imageViews[index] else { continue }
            if imageView.superview == nil
            {
                imageView.layer.isDoubleSided = false
                self.scrollView.addSubview(imageView)
            }

            var angle = (self.scrollOffset - CGFloat(index)) * CGFloat.pi * 0.5
            while angle < 0
            {
                angle += CGFloat.pi * 2.0
            }
            while angle > CGFloat.pi * 2.0
            {
                angle -= CGFloat.pi * 2.0
            }

            var transform = CATransform3DIdentity
            if angle != 0.0
            {
                transform.m34 = -1.0 / 500.0
                transform = CATransform3DTranslate(transform, 0.0, 0.0, -self.view.bounds.width * 0.5)
                transform = CATransform3DRotate(transform, -angle, 0, 1, 0)
                transform = CATransform3DTranslate(transform, 0, 0, self.view.bounds.width * 0.5)
            }

            imageView.bounds = self.view.bounds
            imageView.center = CGPoint(x: self.view.bounds.midX + self.scrollView.contentOffset.x, y: self.view.bounds.midY)
            imageView.layer.transform = transform
        }
    }

    fileprivate func loadUnloadViews()
    {
        var visibleIndices = [Int]()
        visibleIndices.append(self.currentIndex)
        visibleIndices.append(self.currentIndex + 1)

        if self.currentIndex > 0
        {
            visibleIndices.append(self.currentIndex - 1)
        }
        else
        {
            visibleIndices.append(-1)
        }

        for index in 0 ..< self.images.count
        {
            guard !visibleIndices.contains(index) else { continue }

            let imageView = self.imageViews[index]
            imageView?.removeFromSuperview()
            self.imageViews.removeValue(forKey: index)
        }
        for index in visibleIndices
        {
            if let _ = self.imageViews[index]
            {

            }
            else if self.images.count > 0
            {
                let newIndex = (index + self.images.count) % self.images.count
                let imageView = UIImageView(frame: self.view.bounds)
                imageView.contentMode = .scaleAspectFill
                imageView.clipsToBounds = true
                imageView.backgroundColor = .white
                imageView.image = self.images[newIndex]
                self.imageViews[index] = imageView
            }
        }
    }
}

// MARK: - UIScrollViewDelegate
extension CubeScrollViewController: UIScrollViewDelegate
{
    func scrollViewDidScroll(_ scrollView: UIScrollView)
    {
        guard !self.suppressScrollEvent else { return }

        let offset: CGFloat = scrollView.contentOffset.x / self.view.bounds.width
        self.scrollOffset += (offset - self.previousOffset)
        while self.scrollOffset < 0.0
        {
            self.scrollOffset += CGFloat(self.images.count)

        }
        while self.scrollOffset >= CGFloat(self.images.count)
        {
            self.scrollOffset -= CGFloat(self.images.count)

        }
        self.previousOffset = offset

        if offset - floor(offset) == 0.0
        {
            self.scrollOffset = round(self.scrollOffset)

        }
        self.currentIndex = max(0, min(self.images.count - 1, Int(round(self.scrollOffset))))
        self.updateContentOffset()
        self.loadUnloadViews()
        self.updateLayout()
    }

    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView)
    {
        let nearestIntegralOffset = round(self.scrollOffset)
        guard abs(self.scrollOffset - nearestIntegralOffset) > 0.0 else { return }
        self.scrollToImage(at: self.currentIndex)
    }
}
import UIKit

class ViewController: UIViewController
{
    //MARK: - Properties
    private lazy var scrollView: UIScrollView =
    {
        let scrollView = UIScrollView()
        scrollView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
        scrollView.showsHorizontalScrollIndicator = true
        scrollView.isPagingEnabled = true
        scrollView.isDirectionalLockEnabled = true;
        scrollView.autoresizesSubviews = false;
        scrollView.delegate = self
        return scrollView
    }()
    var images = [UIImage]()
    fileprivate var imageViews = [Int: UIImageView]()
    fileprivate var currentIndex = 0
    fileprivate var scrollOffset: CGFloat = 0.0
    fileprivate var previousOffset: CGFloat = 0.0
    fileprivate var suppressScrollEvent = false

    //MARK: - Lifecycle

    override func viewDidLoad()
    {
        super.viewDidLoad()
        self.view.addSubview(self.scrollView)
        for (index, image) in self.images.enumerated()
        {
            let imageView = UIImageView(image: image)
            imageView.contentMode = .scaleAspectFill
            imageView.clipsToBounds = true
            imageView.backgroundColor = UIColor.white
            self.imageViews[index] = imageView
        }
    }

    override func viewDidLayoutSubviews()
    {
        super.viewDidLayoutSubviews()
        self.scrollView.frame = self.view.bounds

        let width = UIScreen.main.bounds.size.width - 80
        let yPos = (UIScreen.main.bounds.size.height / 2) - (width / 2)
        let iFrame = CGRect(x: 40, y: yPos, width: width, height: width)

        self.imageViews.values.forEach {  $0.frame  = iFrame }
        var pages = CGFloat(self.images.count)
        pages = self.images.count > 1 ? pages + 2 : pages
        self.suppressScrollEvent = true
        self.scrollView.contentSize = CGSize(width: self.view.bounds.width * pages, height: self.view.bounds.height)
        self.suppressScrollEvent = false
        self.updateContentOffset()
        self.loadUnloadViews()
        self.updateLayout()
    }


    //MARK: - Exposed Functions
    func set(_ currentImageIndex: Int)
    {
        self.scrollToImage(at: currentIndex)
    }

    func scrollToImage(at index: Int, animated: Bool = true)
    {
        var offset = index > self.images.count ? index % self.images.count : index
        offset = max(-1, offset) + 1
        self.scrollView.setContentOffset(CGPoint(x: self.view.bounds.width * CGFloat(offset), y: 0.0), animated: animated)
    }

    func scrollForward(animated: Bool = true)
    {
        self.scrollToImage(at: self.currentIndex + 1, animated: animated)
    }

    func scrollBack(animated: Bool = true)
    {
        self.scrollToImage(at: self.currentIndex - 1, animated: animated)
    }

    func reloadData()
    {
        self.imageViews.values.forEach { $0.removeFromSuperview() }
    }

    func reloadImage(at index: Int, animated: Bool = true)
    {
        let width = UIScreen.main.bounds.size.width - 80
        let yPos = (UIScreen.main.bounds.size.height / 2) - (width / 2)
        let iFrame = CGRect(x: 40, y: yPos, width: width, height: width)

        guard 0 ..< self.images.count ~= index else { return }
        let image = self.images[index]
        let oldImageView = self.imageViews[index]
        let imageView = UIImageView(frame: iFrame)
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.image = image
        imageView.backgroundColor = .white
        let transform = imageView.layer.transform
        let center = imageView.center

        if animated
        {
            let animation = CATransition()
            animation.type = CATransitionType.fade
            self.scrollView.layer.add(animation, forKey: nil)
        }
        oldImageView?.removeFromSuperview()
        self.scrollView.addSubview(imageView)
        imageView.layer.transform = transform
        imageView.center = center
    }

    //MARK: - Layout
    fileprivate func updateContentOffset()
    {
        guard self.images.count > 1 else { return }

        var offset = self.scrollOffset
        offset += 1.0
        while offset < 1.0
        {
            offset += 1.0
        }
        while offset >= CGFloat(self.images.count + 1)
        {
            offset -= CGFloat(self.images.count)
        }
        self.previousOffset = offset

        self.suppressScrollEvent = true
        self.scrollView.contentOffset = CGPoint(x: self.view.bounds.width * offset, y: 0.0)
        self.suppressScrollEvent = false

    }

    fileprivate func updateLayout()
    {
        let width = UIScreen.main.bounds.size.width - 80
        let yPos = (UIScreen.main.bounds.size.height / 2) - (width / 2)
        let iFrame = CGRect(x: 40, y: yPos, width: width, height: width)

        for index in self.imageViews.keys
        {
            guard let imageView = self.imageViews[index] else { continue }
            if imageView.superview == nil
            {
                imageView.layer.isDoubleSided = false
                self.scrollView.addSubview(imageView)
            }

            var angle = (self.scrollOffset - CGFloat(index)) * CGFloat.pi * 0.5
            while angle < 0
            {
                angle += CGFloat.pi * 2.0
            }
            while angle > CGFloat.pi * 2.0
            {
                angle -= CGFloat.pi * 2.0
            }

            var transform = CATransform3DIdentity
            if angle != 0.0
            {
                transform.m34 = -1.0 / 500.0
                transform = CATransform3DTranslate(transform, 0.0, 0.0, -iFrame.width * 0.5)
                transform = CATransform3DRotate(transform, -angle, 0, 1, 0)
                transform = CATransform3DTranslate(transform, 0, 0, iFrame.width * 0.5)
            }



            imageView.bounds = iFrame
            imageView.center = CGPoint(x: iFrame.midX + self.scrollView.contentOffset.x, y: iFrame.midY)
            imageView.layer.transform = transform
        }
    }

    fileprivate func loadUnloadViews()
    {
        var visibleIndices = [Int]()
        visibleIndices.append(self.currentIndex)
        visibleIndices.append(self.currentIndex + 1)

        if self.currentIndex > 0
        {
            visibleIndices.append(self.currentIndex - 1)
        }
        else
        {
            visibleIndices.append(-1)
        }

        for index in 0 ..< self.images.count
        {
            guard !visibleIndices.contains(index) else { continue }

            let imageView = self.imageViews[index]
            imageView?.removeFromSuperview()
            self.imageViews.removeValue(forKey: index)
        }
        for index in visibleIndices
        {
            if let _ = self.imageViews[index]
            {

            }
            else if self.images.count > 0
            {
                let width = UIScreen.main.bounds.size.width - 80
                let yPos = (UIScreen.main.bounds.size.height / 2) - (width / 2)
                let iFrame = CGRect(x: 40, y: yPos, width: width, height: width)

                let newIndex = (index + self.images.count) % self.images.count
                let imageView = UIImageView(frame: iFrame)
                imageView.contentMode = .scaleAspectFill
                imageView.clipsToBounds = true
                imageView.backgroundColor = .white
                imageView.image = self.images[newIndex]
                self.imageViews[index] = imageView
            }
        }
    }
}

// MARK: - UIScrollViewDelegate
extension ViewController: UIScrollViewDelegate
{
    func scrollViewDidScroll(_ scrollView: UIScrollView)
    {
        guard !self.suppressScrollEvent else { return }

        let offset: CGFloat = scrollView.contentOffset.x / self.view.bounds.width
        self.scrollOffset += (offset - self.previousOffset)
        while self.scrollOffset < 0.0
        {
            self.scrollOffset += CGFloat(self.images.count)

        }
        while self.scrollOffset >= CGFloat(self.images.count)
        {
            self.scrollOffset -= CGFloat(self.images.count)

        }
        self.previousOffset = offset

        if offset - floor(offset) == 0.0
        {
            self.scrollOffset = round(self.scrollOffset)

        }
        self.currentIndex = max(0, min(self.images.count - 1, Int(round(self.scrollOffset))))
        self.updateContentOffset()
        self.loadUnloadViews()
        self.updateLayout()
    }

    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView)
    {
        let nearestIntegralOffset = round(self.scrollOffset)
        guard abs(self.scrollOffset - nearestIntegralOffset) > 0.0 else { return }
        self.scrollToImage(at: self.currentIndex)
    }
}