Move scrollview automatically with page controller - ios

Hi I am using the PageController in my application.
I have inserted all the data on scrollView.
What I want do is, I want to move the scrollview automatically like page control with specific time.
When the scrollView reaches to last page it again recall all pages speedy and start from first onwards.
I want to load/get first page very smoothly after last page completion.
Find my code with following.
var slides:[Slide] = [];
var offSet: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
slides = createSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubview(toFront: pageControl)
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)
}
#objc func autoScroll() {
let totalPossibleOffset = CGFloat(slides.count - 1) * self.view.bounds.size.width
if offSet == totalPossibleOffset {
offSet = 0 // come back to the first image after the last image
}
else {
offSet += self.view.bounds.size.width
}
DispatchQueue.main.async() {
UIView.animate(withDuration: 0.3, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {
self.scrollView.contentOffset.x = CGFloat(self.offSet)
}, completion: nil)
}
}

#objc func autoScroll() {
let totalPossibleOffset = CGFloat(slides.count - 1) * self.view.bounds.size.width
if offSet == totalPossibleOffset {
offSet = 0 // come back to the first image after the last image
}
else {
offSet += self.view.bounds.size.width
}
DispatchQueue.main.async() {
UIView.animate(withDuration: 0.1, delay: 0, options: UIView.AnimationOptions.curveLinear, animations: {
self.scrollView.scroll(topOffset:offSet, animated: true)
}, completion: nil)
}
}
extension UIScrollView {
// Bonus: Scroll
func scroll(topOffset:Float, animated: Bool) {
let ofSetValue = CGPoint(x: topOffset, y: 0)
setContentOffset(ofSetValue, animated: animated)
}
}

Use the following code working fine.
#objc func autoScroll() {
let totalPossibleOffset = CGFloat(slides.count - 1) * self.view.bounds.size.width
if offSet == totalPossibleOffset {
offSet = 0 // come back to the first image after the last image
}
else {
offSet += self.view.bounds.size.width
}
DispatchQueue.main.async() {
UIView.animate(withDuration: 0.0, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {
self.scrollView.contentOffset.x = CGFloat(self.offSet)
}, completion: nil)
}
}

Related

Stop the autoscroll in scrollview on user interaction swift

I using the pagecontroller in my application.
it is working fine every thing it will scroll automatically for every 3 sec time and current position also changed based on user custom swipe.
But I having one issue here when user manually swipe the scrollview on that time I want to stop the auto scroll.
Please find with the my following code.
var slides:[Slide] = [];
var offSet: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
slides = createSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubview(toFront: pageControl)
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(autoScroll), userInfo: nil, repeats: true)
}
#objc func autoScroll() {
let totalPossibleOffset = CGFloat(slides.count - 1) * self.view.bounds.size.width
if offSet == totalPossibleOffset {
offSet = 0 // come back to the first image after the last image
}
else {
offSet += self.view.bounds.size.width
}
DispatchQueue.main.async() {
UIView.animate(withDuration: 0.3, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {
self.scrollView.contentOffset.x = CGFloat(self.offSet)
}, completion: nil)
}
}
Add scroll view delegate and use scrollViewDidEndDragging methods when it calls just reset your timer so after 3 sec start again it working as it is.
The code is untested, You should check with current index with your total number slides count
Create one global index like below and change your conditions. And you need to manage this index while swipe function as well and Invalidate your timer while swipe. Your timer object should be in global
timer.invalidate()
var currentPage = 0
#objc func autoScroll() {
let totalPossibleOffset = 0
if currentPage == slides.count {
currentPage = 0 // come back to the first image after the last image
totalPossibleOffset = 0
}
else {
currentPage = currentPage + 1
totalPossibleOffset = currentPage * self.view.bounds.size.width
}
DispatchQueue.main.async() {
UIView.animate(withDuration: 0.3, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: {
self.scrollView.contentOffset.x = CGFloat(totalPossibleOffset)
}, completion: nil)
}
}

Manage Keyboard in Chat View

I have a controller like chat view, with one textfield and button and table view. I want to when user tap to textfield textfield go up and scroll to end of list. there is my code :
#objc func keyboardWillChangeFrame(_ notification: Notification) {
let keyboardFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue
print("*****************")
print((keyboardFrame?.height)!)
//emoji keyboard size is 258
if (keyboardFrame?.height)! == 258 {
textBackViewBottom.constant = 52
}
else {
textBackViewBottom.constant = 10
}
}
#objc func keyboardWillShow(_ notification: Notification) {
// Check for double invocation
if _keyboardShown {
return
}
_keyboardShown = true
// Reducing size of table
let baseView = self.view
let keyboardFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey]! as AnyObject).cgRectValue
print("////////////////////")
print((keyboardFrame?.height)!)
let keyboardDuration = ((notification as NSNotification).userInfo![UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue
let visibleRows = tableView.indexPathsForVisibleRows
var lastIndexPath : IndexPath? = nil
if (visibleRows != nil) && visibleRows!.count > 0 {
lastIndexPath = visibleRows![visibleRows!.count-1] as IndexPath
}
UIView.animate(withDuration: keyboardDuration!, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
baseView!.frame = CGRect(x: baseView!.frame.origin.x, y: baseView!.frame.origin.y, width: baseView!.frame.size.width, height: baseView!.frame.size.height - (keyboardFrame?.size.height)!)
}, completion: {
(finished: Bool) in
if lastIndexPath != nil {
// Scroll down the table so that the last
// visible row remains visible
self.tableView.scrollToRow(at: lastIndexPath!, at: UITableViewScrollPosition.bottom, animated: true)
}
})
}
#objc func keyboardWillHide(_ notification: Notification) {
// Check for double invocation
if !_keyboardShown {
return
}
_keyboardShown = false
// Expanding size of table
//
let baseView = self.view
let keyboardFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey]! as AnyObject).cgRectValue
let keyboardDuration = ((notification as NSNotification).userInfo![UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue
UIView.animate(withDuration: keyboardDuration!, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
baseView!.frame = CGRect(x: baseView!.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.size.width, height: self.view.frame.size.height + (keyboardFrame?.size.height)!)
}, completion: nil)
}
every thing work well with Iphone default keyboard, but when I'm using custom keyboard like Swiftkey my code is wrong and view broken.
How can get Update view when keyboard size and keyboard type change.
thanks for reply.

UICollectionView show hide animation issue

I am getting animation issue while hiding the UICollectionView. Show animation works fine but when I do the hide animation, it immediately hides the collection view without animation. This is the code :
#objc func openMenu(sender: UIButton) {
if sender.tag == 1 {
self.buttonView.tag = 2
self.arrow.image = UIImage(named: "arrowUp.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = UIScreen.main.bounds.size.height - self.frame.size.height
}, completion: { _ in
})
} else {
self.buttonView.tag = 1
self.arrow.image = UIImage(named: "arrowDown.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = 0
}, completion: { _ in
})
}
}
Output :
The strange thing is, I replaced the collection view with a simple UIView and it works fine. Bottom to top animation works perfectly. Code :
#objc func openMenu(sender: UIButton) {
if sender.tag == 1 {
self.buttonView.tag = 2
self.arrow.image = UIImage(named: "arrowUp.png")
UIView.animate(withDuration: 0.7, animations: {
self.testView.frame.size.height = UIScreen.main.bounds.size.height - self.frame.size.height
}, completion: { _ in
})
} else {
self.buttonView.tag = 1
self.arrow.image = UIImage(named: "arrowDown.png")
UIView.animate(withDuration: 0.7, animations: {
self.testView.frame.size.height = 0
}, completion: { _ in
})
}
}
Output :
Question : Why doesn't that work for UICollectionView ?
Initialisation :
UICollectionView :
self.moduleView = ModulesCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 0), collectionViewLayout: UICollectionViewLayout())
self.parentView.addSubView(self.moduleView)
UIView :
self.testView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 0))
self.parentView.addSubView(self.testView)
You need to use layoutSubViews() method for proper animation. Please change your code as below :
#objc func openMenu(sender: UIButton) {
if sender.tag == 1 {
self.buttonView.tag = 2
self.arrow.image = UIImage(named: "arrowUp.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = UIScreen.main.bounds.size.height - self.frame.size.height
// Add this line
self.moduleView.layoutSubviews()
}, completion: { _ in
})
} else {
self.buttonView.tag = 1
self.arrow.image = UIImage(named: "arrowDown.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = 0
// Add this line
self.moduleView.layoutSubviews()
}, completion: { _ in
})
}
}

How to Animate a UIView n number of times within a loop and track each animation event

UIView.animate(withDuration: 3.0, animations: {
// UIView.setAnimationRepeatCount(3.0)
self.leadng.constant = self.view.frame.size.width + self.vwObj.frame.size.width
self.view.layoutIfNeeded()
}, completion: { finished in
UIView.animate(withDuration: 3.0, animations: {
self.leadng.constant = -(self.vwObj.frame.size.width)
})
})
This is the code i am using for animating a UIView. What i am trying to do is to animate the UIView n number of times. That can be done using UIView.setAnimationRepeatCount(3.0), but the problem is i am having an array of different images which i want to show within the UiView for each animation. Anyone having any idea about how to do that
Use the animatedImage property of UIImage to animate multiple images inside a imageview.
ImageView.image = UIImage.animatedImage(with: myImages, duration: 1.0)
where myImages is array of images you want to animate.
Follow this link for details.
Edit: Definitely a very crude way, but it works.
Declared this at top of class.
let arrayColors = [UIColor.red , UIColor.green, UIColor.blue]
var animationCount = 0
I called animateView() in viewdidload
func animateView() {
self.vwObj.backgroundColor = arrayColors[animationCount]
UIView.animate(withDuration: 3.0, animations: {
self.leadng.constant = self.view.frame.size.width + self.vwObj.frame.size.width
self.view.layoutIfNeeded()
}, completion: { finished in
UIView.animate(withDuration: 3.0, animations: {
self.leadng.constant = 0
self.view.layoutIfNeeded()
}, completion: { finished in
self.animationCount = self.animationCount + 1
if self.animationCount < 3 {
self.animateView()
}
})
})
}
Insted of array of colors, you can use array of images to set imageview.image = arrayImage[animationCount]
Seems solved by the below code:
UIView.animate(withDuration: 3.0, animations: {
print ("Animation Started")
self.leadng.constant = self.view.frame.size.width + self.vwObj.frame.size.width
self.view.layoutIfNeeded()
print ("BeginCounter --- (self.counter)")
}, completion: { finished in
UIView.animate(withDuration: 3.5, animations: {
self.leadng.constant = -(self.vwObj.frame.size.width)
print ("AnimationCompleted")
self.counter = self.counter + 1
print ("CompleteCounter --- \(self.counter)")
//self.displayAnimation()
if (self.counter == 3) {
self.timer?.invalidate()
self.counter = 0
}
})
})
& calling---- timer = Timer.scheduledTimer(timeInterval: 4.0, target: self, selector: #selector(ViewController.displayAnimation), userInfo: nil, repeats: true)

Stop block of animations with UITapGestureRecognizer

I have got this problem with breaking animations block in my app. I am animating an image inside UIScrollView (zooming-in, moving from left to right, zooming-out). Animation is being launched on tap with UITapGestureRecognizer.
The problem is that even though I can zoom-out the image when it is being animated, animations block continues and as a result I get the image off the iPhone screen.
I have tried to use removeAllAnimations() method on both scrollView.layer and view.layer but it seems not to work.
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
setupGestureRecognizer()
}
func setupGestureRecognizer() {
let singleTap = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap(recognizer:)))
singleTap.numberOfTapsRequired = 1
scrollView.addGestureRecognizer(singleTap)
}
func handleSingleTap(recognizer: UITapGestureRecognizer) {
animateRecipeImage()
}
// MARK: - Recipe Image Animation
func animateRecipeImage() {
let offset = CGPoint(x: 0, y: 0)
var middleOffset = CGPoint()
let endOffset = CGPoint(x: (imageView.bounds.width / 2), y: 0)
// To avoid animation in landscape mode we check for current device orientation
if (UIDeviceOrientationIsPortrait(UIDevice.current.orientation)) {
if (scrollView.zoomScale > scrollView.minimumZoomScale) {
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
// Remove all animations and update image contraints to fit the screen
self.scrollView.layer.removeAllAnimations()
self.view.layer.removeAllAnimations()
updateConstraintsForSize(size: view.bounds.size)
} else {
scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true)
let screenWidth = screenSize.width
// Handle big screen sizes
if (screenWidth < self.imageView.bounds.width) {
middleOffset = CGPoint(x: ((self.imageView.bounds.width - screenWidth) * self.scrollView.zoomScale), y: 0)
} else {
middleOffset = CGPoint(x: (self.imageView.frame.width - screenWidth), y: 0)
}
// Start animating the image
UIView.animate(withDuration: 2, delay: 0.5, options: [.allowUserInteraction], animations: {
self.scrollView.setContentOffset(offset, animated: false)
}, completion: { _ in
UIView.animate(withDuration: 4, delay: 0.5, options: [.allowUserInteraction], animations: {
self.scrollView.setContentOffset(middleOffset, animated: false)
}, completion: { _ in
UIView.animate(withDuration: 1.0, delay: 0.2, usingSpringWithDamping: 0.4, initialSpringVelocity: 1.1, options: [.allowUserInteraction], animations: {
self.scrollView.setContentOffset(endOffset, animated: false)
}, completion: nil)
})
})
}
}
}
Any ideas how to break that animations block? The result I would like to achieve is break animation and zoom-out image.

Resources