我想创建一个视图,当水平滚动时,在具有立方体动画效果的UIImage
个对象数组之间进行转换。例如:
有人可以指出我在正确的方向上如何在Swift中使用立方体过渡动画水平滚动UIImage
个对象数组吗?
答案 0 :(得分:4)
它太宽泛而无法解释,但你可以使用这个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)
}
}
}
将多维数据集中所需的图像设置为self.images。当前实现包装图像,这意味着当您在第一个图像上向左滑动时,最后一个图像出现,并在最后一个图像上向右滑动,第一个图像出现。
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)
}
}
答案 1 :(得分:0)
使用Spring animation创建各种动画,包括立方体。并且代码非常少。