I’ve a code that scrolls by means of full-screen photos ahead and backward when tapping the left or proper facet of the display screen. When a picture seems on the display screen, it performs one of many animation sorts: high, backside, left, proper, zoomin, zoomout — every of those animations consists of two sub-animations (the primary animation is quick, and the second is looped).
The issue is that generally, when switching photos, the animation coordinates stack. Below regular circumstances, animations ought to solely have an effect on both X, Y, or Scale. However in my case, it generally occurs that photos transfer diagonally (X + Y), the animation goes past the picture boundaries, and I see black areas on the display screen. This should not occur. How can I repair this?
I am utilizing removeAllAnimations
earlier than every animation, but it surely would not assist.
full code:
class ReaderController: UIViewController, CAAnimationDelegate {
var pagesData = [PageData]()
var index = Int()
var pageIndex: Int = -1
let pageContainer: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let pageViews: [PageLayout] = {
let view = [PageLayout(), PageLayout()]
view[0].translatesAutoresizingMaskIntoConstraints = false
view[1].translatesAutoresizingMaskIntoConstraints = false
return view
}()
personal weak var currentTransitionView: PageLayout?
override func viewDidLoad() {
tremendous.viewDidLoad()
setupViews()
setupConstraints()
pageViews[0].index = index
pageViews[1].index = index
pageViews[0].pageIndex = pageIndex
pageViews[1].pageIndex = pageIndex
pageTransition(animated: false, course: "fromRight")
}
func setupViews() {
pageContainer.addSubview(pageViews[0])
pageContainer.addSubview(pageViews[1])
view.addSubview(pageContainer)
}
func setupConstraints() {
pageContainer.topAnchor.constraint(equalTo: view.topAnchor, fixed: 0.0).isActive = true
pageContainer.bottomAnchor.constraint(equalTo: view.bottomAnchor, fixed: 0.0).isActive = true
pageContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor, fixed: 0.0).isActive = true
pageContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor, fixed: 0.0).isActive = true
pageViews[0].topAnchor.constraint(equalTo: pageContainer.topAnchor).isActive = true
pageViews[0].bottomAnchor.constraint(equalTo: pageContainer.bottomAnchor).isActive = true
pageViews[0].leadingAnchor.constraint(equalTo: pageContainer.leadingAnchor).isActive = true
pageViews[0].trailingAnchor.constraint(equalTo: pageContainer.trailingAnchor).isActive = true
pageViews[1].topAnchor.constraint(equalTo: pageContainer.topAnchor).isActive = true
pageViews[1].bottomAnchor.constraint(equalTo: pageContainer.bottomAnchor).isActive = true
pageViews[1].leadingAnchor.constraint(equalTo: pageContainer.leadingAnchor).isActive = true
pageViews[1].trailingAnchor.constraint(equalTo: pageContainer.trailingAnchor).isActive = true
}
func loadData(fileName: Any) -> PagesData {
var url = NSURL()
url = Bundle.essential.url(forResource: "textual content", withExtension: "json")! as NSURL
let information = strive! Information(contentsOf: url as URL)
let particular person = strive! JSONDecoder().decode(PagesData.self, from: information)
return particular person
}
override func touchesBegan(_ touches: Set, with occasion: UIEvent?) {
for contact in touches {
let location = contact.location(in: view.self)
if view.safeAreaInsets.left > 30 {
if (location.x > self.view.body.measurement.width - (view.safeAreaInsets.left * 1.5)) {
pageTransition(animated: true, course: "fromRight")
} else if (location.x < (view.safeAreaInsets.left * 1.5)) {
pageTransition(animated: true, course: "fromLeft")
}
}
else {
if (location.x > self.view.body.measurement.width - 40) {
pageTransition(animated: true, course: "fromRight")
} else if (location.x < 40) {
pageTransition(animated: true, course: "fromLeft")
}
}
}
}
func pageTransition(animated: Bool, course: String) {
let end result = loadData(fileName: pagesData)
swap course {
case "fromRight":
pageIndex += 1
case "fromLeft":
pageIndex -= 1
default: break
}
pageViews[0].pageIndex = pageIndex
pageViews[1].pageIndex = pageIndex
guard pageIndex >= 0 && pageIndex < end result.pagesData.depend else {
pageIndex = max(0, min(pageIndex, end result.pagesData.depend - 1))
return
}
let fromView = pageViews[0].isHidden ? pageViews[1] : pageViews[0]
let toView = pageViews[0].isHidden ? pageViews[0] : pageViews[1]
toView.imageView.layer.removeAllAnimations()
toView.imageView.rework = .id
toView.configure(theData: end result.pagesData[pageIndex])
if animated {
fromView.isHidden = true
toView.isHidden = false
} else {
fromView.isHidden = true
toView.isHidden = false
}
}
}
class PageLayout: UIView {
var index = Int()
var pageIndex = Int()
let imageView: UIImageView = {
let picture = UIImageView()
picture.contentMode = .scaleAspectFill
picture.translatesAutoresizingMaskIntoConstraints = false
return picture
}()
var imageViewTopConstraint = NSLayoutConstraint()
var imageViewBottomConstraint = NSLayoutConstraint()
var imageViewLeadingConstraint = NSLayoutConstraint()
var imageViewTrailingConstraint = NSLayoutConstraint()
var imagePosition = ""
override init(body: CGRect) {
tremendous.init(body: body)
addSubview(imageView)
setupConstraints()
}
func setupConstraints() {
imageView.layer.removeAllAnimations()
imageView.rework = .id
removeConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint,
imageViewTrailingConstraint])
swap imagePosition {
case "high":
imageView.rework = .id
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: -40.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 0.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: 0.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 0.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
UIView.animate(withDuration: 2.0, delay: 0, choices: [.curveEaseOut, .allowUserInteraction, .beginFromCurrentState], animations: {
self.imageView.rework = CGAffineTransform(translationX: 0, y: 40.0)
}, completion: { _ in
UIView.animate(withDuration: 6.0, delay: 0, choices: [.curveLinear, .autoreverse, .repeat, .beginFromCurrentState, .allowUserInteraction], animations: {
self.imageView.rework = self.imageView.rework.translatedBy(x: 0, y: -40.0)
}, completion: nil)
})
case "backside":
imageView.rework = .id
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: 0.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 40.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: 0.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 0.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
UIView.animate(withDuration: 2.0, delay: 0, choices: [.curveEaseOut, .allowUserInteraction, .beginFromCurrentState], animations: {
self.imageView.rework = CGAffineTransform(translationX: 0, y: -40)
}, completion: { _ in
UIView.animate(withDuration: 6.0, delay: 0, choices: [.curveLinear, .autoreverse, .repeat, .beginFromCurrentState, .allowUserInteraction], animations: {
self.imageView.rework = self.imageView.rework.translatedBy(x: 0, y: 40)
}, completion: nil)
})
case "left":
imageView.rework = .id
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: 0.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 0.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: -40.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 0.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
UIView.animate(withDuration: 2.0, delay: 0, choices: [.curveEaseOut, .allowUserInteraction, .beginFromCurrentState], animations: {
self.imageView.rework = CGAffineTransform(translationX: 40, y: 0)
}, completion: { _ in
UIView.animate(withDuration: 6.0, delay: 0, choices: [.curveLinear, .autoreverse, .repeat, .beginFromCurrentState, .allowUserInteraction], animations: {
self.imageView.rework = self.imageView.rework.translatedBy(x: -40, y: 0)
}, completion: nil)
})
case "proper":
imageView.rework = .id
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: 0.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 0.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: 0.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 40.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
UIView.animate(withDuration: 2.0, delay: 0, choices: [.curveEaseOut, .allowUserInteraction, .beginFromCurrentState], animations: {
self.imageView.rework = CGAffineTransform(translationX: -40, y: 0)
}, completion: { _ in
UIView.animate(withDuration: 6.0, delay: 0, choices: [.curveLinear, .autoreverse, .repeat, .beginFromCurrentState, .allowUserInteraction], animations: {
self.imageView.rework = self.imageView.rework.translatedBy(x: 40, y: 0)
}, completion: nil)
})
case "zoomin":
imageView.rework = CGAffineTransformScale(.id, 1.0, 1.0)
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: 0.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 0.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: 0.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 0.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
UIView.animate(withDuration: 2.0, delay: 0, choices: [.curveEaseOut, .allowUserInteraction, .beginFromCurrentState], animations: {
self.imageView.rework = CGAffineTransform(scaleX: 1.1, y: 1.1)
}, completion: { _ in
UIView.animate(withDuration: 6.0, delay: 0, choices: [.curveLinear, .autoreverse, .repeat, .beginFromCurrentState, .allowUserInteraction], animations: {
self.imageView.rework = .id
}, completion: nil)
})
case "zoomout":
imageView.rework = CGAffineTransformScale(.id, 1.1, 1.1)
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: 0.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 0.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: 0.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 0.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
UIView.animate(withDuration: 2.0, delay: 0, choices: [.curveEaseOut, .allowUserInteraction, .beginFromCurrentState], animations: {
self.imageView.rework = CGAffineTransform(scaleX: 1.0, y: 1.0)
}, completion: { _ in
UIView.animate(withDuration: 6.0, delay: 0, choices: [.curveLinear, .autoreverse, .repeat, .beginFromCurrentState, .allowUserInteraction], animations: {
self.imageView.rework = self.imageView.rework.scaledBy(x: 1.1, y: 1.1)
}, completion: nil)
})
default:
imageView.rework = .id
imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor, fixed: 0.0)
imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor, fixed: 0.0)
imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, fixed: 0.0)
imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor, fixed: 0.0)
addConstraints([imageViewTopConstraint, imageViewBottomConstraint, imageViewLeadingConstraint, imageViewTrailingConstraint])
}
}
func configure(theData: PageData) {
imageView.picture = UIImage(named: "web page(pageIndex+1)")
imagePosition = theData.imagePosition
setupConstraints()
}
required init?(coder: NSCoder) {
fatalError("Not taking place")
}
}
struct PagesData: Decodable {
var pagesData: [PageData]
}
struct PageData: Decodable {
let textData, textPosition, textColor, shadowColor, textAlignment, imagePosition: String
}
JSON:
{
"pagesData" : [
{
"textData" : "",
"textPosition" : "topLeft",
"textColor" : "FFFFFF",
"shadowColor" : "000000",
"textAlignment" : "left",
"imagePosition" : "left",
},
{
"textData" : "",
"textPosition" : "bottomLeft",
"textColor" : "FFFFFF",
"shadowColor" : "000000",
"textAlignment" : "left",
"imagePosition" : "bottom",
},
{
"textData" : "",
"textPosition" : "zoomin",
"textColor" : "FFFFFF",
"shadowColor" : "000000",
"textAlignment" : "left",
"imagePosition" : "right",
},
{
"textData" : "",
"textPosition" : "bottomCenter",
"textColor" : "FFFFFF",
"shadowColor" : "000000",
"textAlignment" : "left",
"imagePosition" : "zoomout",
},
{
"textData" : "",
"textPosition" : "topLeft",
"textColor" : "FFFFFF",
"shadowColor" : "000000",
"textAlignment" : "left",
"imagePosition" : "left",
},
]
}