UICollectionView InfinityScroll jump effects - ios

i'm making an messenger app, like telegram, i would like to implement an infinite scroll, i use JSQMessageViewController for the chat.
this is the code for infinite scroll:
override func scrollViewDidScroll(scrollView: UIScrollView) {
if(scrollView.contentOffset.y >= 0.0 && scrollView.contentOffset.y <= 30.0 && loading == true){
self.loading = false
self.loadMore()
}
}
Then i call this function:
func loadMore() {
//Controllo se nell'array sono presenti altri messaggi
if ((chatList?.messages.count)!-1) != self.messages.count{
//
CATransaction.begin()
CATransaction.setDisableActions(true)
let oldBottomOffset = self.collectionView!.contentSize.height - self.collectionView!.contentOffset.y
UIView.performWithoutAnimation({ () -> Void in
self.collectionView!.performBatchUpdates({ () -> Void in
let idInit = (self.lastMessageId-self.messagePerPage<0) ? 0 : self.lastMessageId-1-self.messagePerPage
let idEnd = self.lastMessageId-1
var indexPaths: [NSIndexPath] = []
for(var i = 0; i<idEnd-idInit; i++){
print("Creo indexpath \(i)")
indexPaths.append(NSIndexPath(forItem: i, inSection: 0))
}
self.collectionView!.insertItemsAtIndexPaths(indexPaths)
let msg = self.chatList?.messages
var i = idEnd
repeat {
let mg = msg![i]
let messagechat:JSQMessage = JSQMessage(senderId: mg.sender, senderDisplayName: "", date:mg.time, text: mg.message)
messagechat.xmppMessageID = mg.messageID
messagechat.status = mg.messageStatus
self.messages.insert(messagechat, atIndex: 0)
self.lastMessageId = i
i--
} while i > idInit
// invalidate layout
self.collectionView!.collectionViewLayout.invalidateLayoutWithContext(JSQMessagesCollectionViewFlowLayoutInvalidationContext())
}, completion: {(finished) in
//scroll back to current position
self.finishReceivingMessageAnimated(false)
self.collectionView!.layoutIfNeeded()
self.collectionView!.contentOffset = CGPointMake(0, self.collectionView!.contentSize.height - oldBottomOffset)
CATransaction.commit()
})
})
}
else {
print("No more messages to load.")
}
}
All work fine but while scrolling the scroll is stopped for 1sec. i suppose is CATransaction that make this and sometimes i see a jump effect, if i add 10 new messages i see for a second the first message of the 10, and then offset is set correctly to the older position.
How can i fix this? i see telegram scrolling is perfect, and there is no jump effects while loading old messages.

Related

Why pagination scroll is not working on iPhone12(notch display screens)

With the below code I'm able to scroll all cells upto bottom in iPhone 8 but when I run this code in iPhone12 and iPhone11 its not scrolling to bottom.. here showing only 10 cells but the delegate method is calling
here count parameter is page.. each time it displays 10 cells.. like.. when I reach this screen initially it shows 10 cells that's it if there are more products still. it's not scrolling
override func viewDidLoad() {
super.viewDidLoad()
// using framework
let bottomRefreshController = UIRefreshControl()
bottomRefreshController.triggerVerticalOffset = 50
bottomRefreshController.addTarget(self, action: #selector(refresh), for: .valueChanged)
self.collectionView.bottomRefreshControl = bottomRefreshController
self.collectionView.bottomRefreshControl?.tintColor = .clear
}
#objc func refresh() {
serviceCall()
}
fileprivate func allProductsServiceCall(){
let param = ["params": ["category" : catId,
"sub_category" : self.subCatId,
"brands": brands,
"count" : self.currentPageNumber
]] as [String : Any]
APIReqeustManager.sharedInstance.serviceCall(param: param, vc: self, url: getUrl(of: .all_products/*.search*/), header: header) {(responseData) in
if responseData.error != nil{
self.view.makeToast(NSLocalizedString("Something went wrong!", comment: ""))
}else{
if (SearchDataModel(dictionary: responseData.dict as NSDictionary? ?? NSDictionary())?.result?.products ?? [Products]()).count == 0 {
self.view.makeToast("No product to show!".localizeWithLanguage)
return
}
if self.currentPageNumber > 0 {
if (SearchDataModel(dictionary: responseData.dict as NSDictionary? ?? NSDictionary())?.result?.products ?? [Products]()).count > 0 {
self.searchResultData?.result?.products! += SearchDataModel(dictionary: responseData.dict as NSDictionary? ?? NSDictionary())?.result?.products ?? [Products]()
}else {
self.view.makeToast("No more products to show!".localizeWithLanguage)
}
self.productCollectionView.bottomRefreshControl?.endRefreshing()
self.currentPageNumber+=1
DispatchQueue.main.async{
self.productCollectionView.reloadData()
}
}
}
}
// Scroll delegates
// Things needed for expand / collapse
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y + scrollView.frame.size.height) == scrollView.contentSize.height {
print("at the end")
self.productCollectionView.bounces = true
}else {
print("at the middle, moving down")
}
}
The code is working fine. I mean how I want to show it's coming like that in iPhone8 but, why the scrolling with pagination is not working in iPhone12.
where am I wrong.. please do help... I got stuck here for long

how to get indexpath of tableView in any method

I'm trying to show animation if the indexPath == 0 and scroll direction is downward, but I'm unable to get the indexPath of tableView in scrollViewdidScroll method. here's my code -->
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let indexPath = tableView.indexPath(for: ThirdTableViewCell() as UITableViewCell)
if (self.lastContentOffset > scrollView.contentOffset.y) && indexPath?.row == 0 {
print ("up")
}
else if (self.lastContentOffset < scrollView.contentOffset.y) {
// print ("down")
}
self.lastContentOffset = scrollView.contentOffset.y
}
I got the indexPath nil while debugging
You still haven't explained what you really want to do, but maybe this will help...
Start by setting up your scrollViewDidScroll like this:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var partOfRowZeroIsVisible: Bool = false
var topOfRowZeroIsVisible: Bool = false
var userIsDraggingDown: Bool = false
// if user pulls table DOWN when Row Zero is at top,
// contentOffset.y will be negative and table will
// bounce back up...
// so, we make y AT LEAST 0.0
let y = max(0.0, tableView.contentOffset.y)
// point for the top visible content
let pt: CGPoint = CGPoint(x: 0, y: y)
if let idx = tableView.indexPathForRow(at: pt), idx.row == 0 {
// At least PART of Row Zero is visible...
partOfRowZeroIsVisible = true
} else {
// Row Zero is NOT visible...
partOfRowZeroIsVisible = false
}
if y == 0 {
// Table view is scrolled all the way to the top...
topOfRowZeroIsVisible = true
} else {
// Table view is NOT scrolled all the way to the top...
topOfRowZeroIsVisible = false
}
if (self.lastContentOffset >= y) {
// User is DRAGGING the table DOWN
userIsDraggingDown = true
} else {
// User is DRAGGING the table UP
userIsDraggingDown = false
}
// save current offset
self.lastContentOffset = y
Then, to show or hide your "arrow":
// if you want to show your "arrow"
// when ANY PART of Row Zero is visible
if partOfRowZeroIsVisible {
arrow.isHidden = false
} else {
arrow.isHidden = true
}
or:
// if you want to show your "arrow"
// ONLY when table view has been scrolled ALL THE WAY to the top
if topOfRowZeroIsVisible {
arrow.isHidden = false
} else {
arrow.isHidden = true
}
or:
// if you want to show your "arrow"
// when ANY PART of Row Zero is visible
// and
// ONLY if the user is dragging DOWN
if partOfRowZeroIsVisible && userIsDraggingDown {
arrow.isHidden = false
} else {
arrow.isHidden = true
}
or:
// if you want to show your "arrow"
// ONLY when table view has been scrolled ALL THE WAY to the top
// and
// ONLY if the user is dragging DOWN
if topOfRowZeroIsVisible && userIsDraggingDown {
arrow.isHidden = false
} else {
arrow.isHidden = true
}

Swiping left to create a new collectionViewCell

I'm trying to implement a smoother way for a use to add new collectionViewCells for myCollectionView (which only shows one cell at a time). I want it to be something like when the user swipes left and if the user is on the last cell myCollectionView inserts a new cell when the user is swiping so that the user swipes left "into" the cell. And also I only allow the user to scroll one cell at a time.
EDIT:
So I think it is a bit hard to describe it in words so here is a gif to show what I mean
So in the past few weeks I have been trying to implement this in a number of different ways, and the one that I have found the most success with is by using the scrollViewWillEndDragging delegate method and I have implemented it like this:
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Getting the size of the cells
let flowLayout = myCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
let cellWidth = flowLayout.itemSize.width
let cellPadding = 10.0 as! CGFloat
// Calculating which page "card" we should be on
let currentOffset = scrollView.contentOffset.x - cellWidth/2
print("currentOffset is \(currentOffset)")
let cardWidth = cellWidth + cellPadding
var page = Int(round((currentOffset)/(cardWidth) + 1))
print("current page number is: \(page)")
if (velocity.x < 0) {
page -= 1
}
if (velocity.x > 0) {
page += 1
}
print("Updated page number is: \(page)")
print("Previous page number is: \(self.previousPage)")
// Only allowing the user to scroll for one page!
if(page > self.previousPage) {
page = self.previousPage + 1
self.previousPage = page
}
else if (page == self.previousPage) {
page = self.previousPage
}
else {
page = self.previousPage - 1
self.previousPage = page
}
print("new page number is: " + String(page))
print("addedCards.count + 1 is: " + String(addedCards.count + 1))
if (page == addedCards.count) {
print("reloading data")
// Update data source
addedCards.append("card")
// Method 1
cardCollectionView.reloadData()
// Method 2
// let newIndexPath = NSIndexPath(forItem: addedCards.count - 1, inSection: 0)
// cardCollectionView.insertItemsAtIndexPaths([newIndexPath])
}
// print("Centering on new cell")
// Center the cardCollectionView on the new page
let newOffset = CGFloat(page * Int((cellWidth + cellPadding)))
print("newOffset is: \(newOffset)")
targetContentOffset.memory.x = newOffset
}
Although I think I have nearly got the desired result there are still some concerns and also bugs that I have found.
My main concern is the fact that instead of inserting a single cell at the end of myCollectionView I'm reloading the whole table. The reason that I do this is because if I didn't then myCollectionView.contentOffset wouldn't be changed and as a result when a new cell is created, myCollectionView isn't centered on the newly created cell.
1. If the user scrolls very slowly and then stops, the new cell gets created but then myCollectionView gets stuck in between two cells it doesn't center in on the newly created cell.
2. When myCollectionView is in between the second last cell and the last cell as a result of 1., the next time the user swipes right, instead of creating one single cell, two cells are created.
I've also used different ways to implement this behaviour such as using scrollViewDidScroll, and various other but to no avail. Can anyone point me in the right direction as I am kind of lost.
Here is a link to download my project if you want to see the interaction:
My Example Project
These the old methods if you're interested:
To do this I have tried 2 ways,
The first being:
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint,
targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// page is the current cell that the user is on
// addedCards is the array that the data source works with
if (page == addedCards.count + 1) {
let placeholderFlashCardProxy = FlashCardProxy(phrase: nil, pronunciation: nil, definition: nil)
addedCards.append(placeholderFlashCardProxy)
let newIndexPath = NSIndexPath(forItem: addedCards.count, inSection: 0)
cardCollectionView.insertItemsAtIndexPaths([newIndexPath])
cardCollectionView.reloadData()
}
}
The problem with using this method is that:
Sometimes I will get a crash as a result of: NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0.
When a new collectionCell is added it will sometimes display the input that the user has written from the previous cell (this might have sometimes to do with the dequeuing and re-use of cell, although again, I'm not sure and I would be grateful if someone answered it)
The inserting isn't smooth, I want the user to be able to swipe left at the last cell and "into" a new cell. As in if I am currently on the last cell, swiping left would put me automatically at the new cell, because right now when I swipe left a new cell is created by it doesn't center on the newly created cell
The second method that I am using is:
let swipeLeftGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "swipedLeftOnCell:")
swipeLeftGestureRecognizer.direction = .Left
myCollectionView.addGestureRecognizer(swipeLeftGestureRecognizer)
swipeLeftGestureRecognizer.delegate = self
Although the swipe gesture very rarely responds, but if I use a tap gesture, myCollectionView always responds which is very weird (I know again this is a question on its own)
My question is which is the better way to implement what I have described above? And if none are good what should I work with to create the desired results, I've been trying to do this for two days now and I was wondering if someone could point me in the right direction. Thanks!
I hope this helps out in some way :)
UPDATE
I updated the code to fix the issue scrolling in either direction.
The updated gist can be found here
New Updated Gist
Old Gist
First I'm gonna define some model to for a Card
class Card {
var someCardData : String?
}
Next, create a collection view cell, with a card view inside that we will apply the transform to
class CollectionViewCell : UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(cardView)
self.addSubview(cardlabel)
}
override func prepareForReuse() {
super.prepareForReuse()
cardView.alpha = 1.0
cardView.layer.transform = CATransform3DIdentity
}
override func layoutSubviews() {
super.layoutSubviews()
cardView.frame = CGRectMake(contentPadding,
contentPadding,
contentView.bounds.width - (contentPadding * 2.0),
contentView.bounds.height - (contentPadding * 2.0))
cardlabel.frame = cardView.frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
lazy var cardView : UIView = {
[unowned self] in
var view = UIView(frame: CGRectZero)
view.backgroundColor = UIColor.whiteColor()
return view
}()
lazy var cardlabel : UILabel = {
[unowned self] in
var label = UILabel(frame: CGRectZero)
label.backgroundColor = UIColor.whiteColor()
label.textAlignment = .Center
return label
}()
}
Next setup the view controller with a collection view. As you will see there is a CustomCollectionView class, which I will define near the end.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var cards = [Card(), Card()]
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
collectionView.frame = CGRectMake(0, 0, self.view.bounds.width, tableViewHeight)
collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, contentPadding)
}
lazy var collectionView : CollectionView = {
[unowned self] in
// MARK: Custom Flow Layout defined below
var layout = CustomCollectionViewFlowLayout()
layout.contentDelegate = self
var collectionView = CollectionView(frame: CGRectZero, collectionViewLayout : layout)
collectionView.clipsToBounds = true
collectionView.showsVerticalScrollIndicator = false
collectionView.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
collectionView.delegate = self
collectionView.dataSource = self
return collectionView
}()
// MARK: UICollectionViewDelegate, UICollectionViewDataSource
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return cards.count
}
func collectionView(collectionView : UICollectionView, layout collectionViewLayout:UICollectionViewLayout, sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize {
return CGSizeMake(collectionView.bounds.width, tableViewHeight)
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cellIdentifier = "CollectionViewCell"
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as! CollectionViewCell
cell.contentView.backgroundColor = UIColor.blueColor()
// UPDATE If the cell is not the initial index, and is equal the to animating index
// Prepare it's initial state
if flowLayout.animatingIndex == indexPath.row && indexPath.row != 0{
cell.cardView.alpha = 0.0
cell.cardView.layer.transform = CATransform3DScale(CATransform3DIdentity, 0.0, 0.0, 0.0)
}
return cell
}
}
UPDATED - Now For the really tricky part. I'm gonna define the CustomCollectionViewFlowLayout. The protocol callback returns the next insert index calculated by the flow layout
protocol CollectionViewFlowLayoutDelegate : class {
func flowLayout(flowLayout : CustomCollectionViewFlowLayout, insertIndex index : NSIndexPath)
}
/**
* Custom FlowLayout
* Tracks the currently visible index and updates the proposed content offset
*/
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
weak var contentDelegate: CollectionViewFlowLayoutDelegate?
// Tracks the card to be animated
// TODO: - Adjusted if cards are deleted by one if cards are deleted
private var animatingIndex : Int = 0
// Tracks thje currently visible index
private var visibleIndex : Int = 0 {
didSet {
if visibleIndex > oldValue {
if visibleIndex > animatingIndex {
// Only increment the animating index forward
animatingIndex = visibleIndex
}
if visibleIndex + 1 > self.collectionView!.numberOfItemsInSection(0) - 1 {
let currentEntryIndex = NSIndexPath(forRow: visibleIndex + 1, inSection: 0)
contentDelegate?.flowLayout(self, insertIndex: currentEntryIndex)
}
} else if visibleIndex < oldValue && animatingIndex == oldValue {
// if we start panning to the left, and the animating index is the old value
// let set the animating index to the last card.
animatingIndex = oldValue + 1
}
}
}
override init() {
super.init()
self.minimumInteritemSpacing = 0.0
self.minimumLineSpacing = 0.0
self.scrollDirection = .Horizontal
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// The width offset threshold percentage from 0 - 1
let thresholdOffsetPrecentage : CGFloat = 0.5
// This is the flick velocity threshold
let velocityThreshold : CGFloat = 0.4
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
let leftThreshold = CGFloat(collectionView!.bounds.size.width) * ((CGFloat(visibleIndex) - 0.5))
let rightThreshold = CGFloat(collectionView!.bounds.size.width) * ((CGFloat(visibleIndex) + 0.5))
let currentHorizontalOffset = collectionView!.contentOffset.x
// If you either traverse far enought in either direction,
// or flicked the scrollview over the horizontal velocity in either direction,
// adjust the visible index accordingly
if currentHorizontalOffset < leftThreshold || velocity.x < -velocityThreshold {
visibleIndex = max(0 , (visibleIndex - 1))
} else if currentHorizontalOffset > rightThreshold || velocity.x > velocityThreshold {
visibleIndex += 1
}
var _proposedContentOffset = proposedContentOffset
_proposedContentOffset.x = CGFloat(collectionView!.bounds.width) * CGFloat(visibleIndex)
return _proposedContentOffset
}
}
And define the delegate methods in your view controller to insert a new card when the delegate tell it that it needs a new index
extension ViewController : CollectionViewFlowLayoutDelegate {
func flowLayout(flowLayout : CustomCollectionViewFlowLayout, insertIndex index : NSIndexPath) {
cards.append(Card())
collectionView.performBatchUpdates({
self.collectionView.insertItemsAtIndexPaths([index])
}) { (complete) in
}
}
And below is the custom Collection view that applies the animation while scrolling accordingly :)
class CollectionView : UICollectionView {
override var contentOffset: CGPoint {
didSet {
if self.tracking {
// When you are tracking the CustomCollectionViewFlowLayout does not update it's visible index until you let go
// So you should be adjusting the second to last cell on the screen
self.adjustTransitionForOffset(NSIndexPath(forRow: self.numberOfItemsInSection(0) - 1, inSection: 0))
} else {
// Once the CollectionView is not tracking, the CustomCollectionViewFlowLayout calls
// targetContentOffsetForProposedContentOffset(_:withScrollingVelocity:), and updates the visible index
// by adding 1, thus we need to continue the trasition on the second the last cell
self.adjustTransitionForOffset(NSIndexPath(forRow: self.numberOfItemsInSection(0) - 2, inSection: 0))
}
}
}
/**
This method applies the transform accordingly to the cell at a specified index
- parameter atIndex: index of the cell to adjust
*/
func adjustTransitionForOffset(atIndex : NSIndexPath) {
if let lastCell = self.cellForItemAtIndexPath(atIndex) as? CollectionViewCell {
let progress = 1.0 - (lastCell.frame.minX - self.contentOffset.x) / lastCell.frame.width
lastCell.cardView.alpha = progress
lastCell.cardView.layer.transform = CATransform3DScale(CATransform3DIdentity, progress, progress, 0.0)
}
}
}
I think u missed one point here in
let newIndexPath = NSIndexPath(forItem: addedCards.count, inSection: 0)
the indexPath should be
NSIndexPath(forItem : addedCards.count - 1, inSection : 0) not addedCards.count
Thats why you were getting the error
NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0

Swift UIView appearing in different places

Im trying to make a small game. And there is some problem with the animation. Im new to Swift. So lets take a look. I create a UIImageView picture and want to do animation of this picture appear in a different places on a screen. I believe that the algorithm will look like this:
Infinite loop{
1-GetRandomPlace
2-change opacity from 0 to 1 and back(with smooth transition)
}
Looks simple, but I can't understand how to do it correctly in Xcode.
Here is my test code but it looks useless
Thank you for help and sorry if there was already this question, I can't find it.
class ViewController: UIViewController {
#IBOutlet weak var BackgroundMainMenu:UIImageView!
#IBOutlet weak var AnimationinMenu: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// MoveBackgroundObject(AnimationinMenu)
// AnimationBackgroundDots(AnimationinMenu, delay: 0.0)
// self.AnimationinMenu.alpha = 0
//
// UIImageView.animateWithDuration(3.0,
// delay: 0.0,
// options: UIViewAnimationOptions([.Repeat, .CurveEaseInOut]),
// animations: {
// self.MoveBackgroundObject(self.AnimationinMenu)
// self.AnimationinMenu.alpha = 1
// self.AnimationinMenu.alpha = 0
// },
// completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
AnimationBackgroundDots(AnimationinMenu, delay: 0.0)
}
func ChangeOpacityto1(element: UIImageView){
element.alpha = 0
UIView.animateWithDuration(3.0) {
element.alpha = 1
}
}
func ChangeOpacityto0(element: UIImageView){
element.alpha = 1
UIView.animateWithDuration(3.0){
element.alpha = 0
}
}
func AnimationBackgroundDots(element: UIImageView, delay: Double){
element.alpha = 0
var z = 0
while (z<4){
MoveBackgroundObject(AnimationinMenu)
UIImageView.animateWithDuration(3.0,
animations: {
element.alpha = 0
element.alpha = 1
element.alpha = 0
},
completion: nil)
z++
}
}
func MoveBackgroundObject(element: UIImageView) {
// Find the button's width and height
let elementWidth = element.frame.width
let elementHeight = element.frame.height
// Find the width and height of the enclosing view
let viewWidth = BackgroundMainMenu.superview!.bounds.width
let viewHeight = BackgroundMainMenu.superview!.bounds.height
// Compute width and height of the area to contain the button's center
let xwidth = viewWidth - elementWidth
let yheight = viewHeight - elementHeight
// Generate a random x and y offset
let xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))
let yoffset = CGFloat(arc4random_uniform(UInt32(yheight)))
// Offset the button's center by the random offsets.
element.center.x = xoffset + elementWidth / 2
element.center.y = yoffset + elementHeight / 2
}
}
The problem is in AnimationBackgroundDots.
You are immediately creating 4 animations on the same view but only one can run at a time. What you need to do is wait until one animation is finished (fade in or fade out) before starting a new one.
Also, the animations closure is for setting the state you want your view to animate to. It looks at how your view is at the start, runs animations, then looks at the view again and figures out how to animate between the two. In your case, the alpha of the UIImageView starts at 0, then when animations runs, the alpha ends up being 0 so nothing would animate. You can't create all the steps an animation should take that way.
Want you need to do it move your view and start the fade in animation. The completion closure of fading in should start the fade out animation. The completion closure of the fading out should then start the process all over again. It could look something like this.
func AnimationBackgroundDots(element: UIImageView, times: Int) {
guard times > 0 else {
return
}
MoveBackgroundObject(element)
element.alpha = 1
// Fade in
UIView.animateWithDuration(3.0, animations: {
element.alpha = 1
}, completion: { finished in
// Fade Out
UIView.animateWithDuration(3.0, animations: {
element.alpha = 0
}, completion: { finished in
// Start over again
self.AnimationBackgroundDots(element, times: times-1)
})
})
}
You called also look at using keyframe animations but this case is simple enough that theres no benefit using them.
Also as a side note. The function naming convention in swift is to start with a lowercase letter, so AnimationBackgroundDots should be animationBackgroundDots.

Make scrollView page show text in array

I have a scrollView that shows the first item in my Array, but I cannot get the second item to show when I scroll to the next page. Also, the text from first item in the Array shows when I am on the second page of the scrollView.
Could someone please help?
func scrollViewDidScroll(scrollView: UIScrollView)
{
var pageSize: Float = Float(scrollView.bounds.size.width)
var page: Float = floorf((Float(scrollView.contentOffset.x) - (pageSize/2.0)) / pageSize) + 1
//Bind Page limits
if (page >= Float(numpages)){
page = Float(numpages) - 1
} else if (page < 0) {
page = 0
}
pageControl.currentPage = Int(page)
question.text = featureQuestions[pageControl.currentPage]
println(pageControl.currentPage)
}
override func viewWillAppear(animated: Bool)
{
for var q = 0; q < numpages; q++
{
let mainFrame : CGRect = CGRectMake(scrollView.frame.size.width * CGFloat(q), 0, scrollView.frame.size.width, scrollView.frame.size.height)
var question : UILabel = UILabel(frame: scrollView.frame)
question.clipsToBounds = true
scrollView.addSubview(question)
}
}
You need to set the frame for question to be mainFrame not scrollView.frame.

Resources