Scrollview not scrolling in right - ios

I have a scroll vie and i want to display the images selected by user in horizontal scroll manner. The following is my code. but, I am unable to achieve that. please guide me.
var xPosition: CGFloat = 0
var scrollViewContentWidth: CGFloat = 398
func handlePickedImage(image: UIImage){
let imageView = UIImageView(image: image)
imageView.frame = CGRect(x: 0, y: 0, width: 398, height: 188)
imageView.contentMode = UIView.ContentMode.scaleAspectFit
imageView.frame.origin.x = xPosition
imageView.frame.origin.y = 10
let spacer: CGFloat = 10
xPosition = 398 + spacer
scrollViewContentWidth = scrollViewContentWidth + spacer
imageScrollView.contentSize = CGSize(width: scrollViewContentWidth, height: 188)
imageScrollView.addSubview(imageView)
}

I have created just that with this code, it also has pagination implemented in it:
import UIKit
class ImagePagerViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var data: [FoodPostImageObject] = []
var userId: Int?
var indexPath: IndexPath?
var page: Int = 1
var alreadyFetchingData = false
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.scrollDirection = .horizontal
collectionView.collectionViewLayout = layout
if userId != nil {
getUserImages()
}
}
override func viewDidLayoutSubviews() {
guard self.indexPath != nil else {return}
self.collectionView.scrollToItem(at: self.indexPath!, at: .right, animated: false)
}
}
extension ImagePagerViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImagePagerCell", for: indexPath) as! ImagePagerCollectionViewCell
cell.image.loadImageUsingUrlString(urlString: data[indexPath.row].food_photo)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
}
extension ImagePagerViewController {
func fetchMoreData(){
if !alreadyFetchingData {
if userId != nil {
getUserImages()
}
}
}
func getUserImages(){
guard let userId = self.userId else {return}
alreadyFetchingData = true
Server.get("/user_images/\(userId)/\(page)/"){ data, response, error in
self.alreadyFetchingData = false
guard let data = data else {return}
do {
self.data.append(contentsOf: try JSONDecoder().decode([FoodPostImageObject].self, from: data))
DispatchQueue.main.async {
self.collectionView.reloadData()
self.collectionView.scrollToItem(at: self.indexPath!, at: .right, animated: false)
self.page += 1
}
} catch {}
}
}
}
and this UICollectionViewCell:
import UIKit
class ImagePagerCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var image: CellImageView!
}
In the storyboard I just have a collectionView and ImagePagerCollectionViewCell inside.
Hope this helps

Related

How to smoothly animate transition cells in uicollectionview in custom flowLayout

I want to create an app that shows an array of photos with captions (for now I have empty circles) that are arranged in horizontal uicollectionview. I want to make one larger circle to be displayed in the center of the screen, but the remaining circles in the line to be smaller and shaded. I did it by creating my own layout for uicollectionview. But I have one problem that I don't know how to fix it. I want the transition between circles to be smoothly animated. Here is an example of what I've done:
I want to achieve something like this:gif
I know that there are some library and frameworks which do that, but I'd like to do by my own.
Here is my code:
class FlowViewController: UIViewController {
let cellWidth : CGFloat = 275
let cellHeight : CGFloat = 300
let cellSpacing : CGFloat = 10
private let circleCollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())
private let layout = myCarouselFlowLayout()
private let collectionViewCellIdentifier = "PositionCollectionViewCell"
private var circles : [myCircle] = {
let pok1 = myCircle(name: "Bl4")
let pok2 = myCircle(name: "Bl3")
let pok3 = myCircle(name: "Bli")
let pok4 = myCircle(name: "Bl0")
let pok5 = myCircle(name: "Lal")
let pok6 = myCircle(name: "Te")
let pok7 = myCircle(name: "wTW")
let pok8 = myCircle(name: "H3RHG")
return [pok1, pok2, pok3, pok4, pok5, pok6, pok7, pok8]
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
view.addSubview(circleCollectionView)
configureCollectionView()
print(circles.count)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
configureCollectionViewLayoutItemSize()
}
func configureCollectionView(){
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: cellWidth, height: cellHeight)
layout.minimumLineSpacing = cellSpacing
//set layout
circleCollectionView.setCollectionViewLayout(layout, animated: true)
//set delegates
setTableViewDelegates()
//register cells
circleCollectionView.register(CircleCollectionViewCell.self, forCellWithReuseIdentifier: collectionViewCellIdentifier)
//set contraits
circleCollectionView.translatesAutoresizingMaskIntoConstraints = false
circleCollectionView.heightAnchor.constraint(equalToConstant: cellHeight).isActive = true
circleCollectionView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
circleCollectionView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
circleCollectionView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
circleCollectionView.backgroundColor = .clear
circleCollectionView.decelerationRate = .fast
}
func calculateSectionInset() -> CGFloat { // should be overridden
let viewWith = UIScreen.main.bounds.size.width
return ( viewWith - cellWidth ) / 2
}
private func configureCollectionViewLayoutItemSize() {
let inset: CGFloat = calculateSectionInset()
layout.sectionInset = UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset)
layout.itemSize = CGSize(width: layout.collectionView!.frame.size.width - inset * 2,
height: layout.collectionView!.frame.size.height)
}
}
extension FlowViewController: UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
circles.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellIdentifier, for: indexPath) as? CircleCollectionViewCell else {
fatalError("Bad instance of FavoritesCollectionViewCell")
}
cell.nameLabel.text = circles[indexPath.row].name
return cell
}
func setTableViewDelegates(){
circleCollectionView.delegate = self
circleCollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(circles.count)
}
}
extension FlowViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = cellWidth
let height = cellHeight
return CGSize(width: width, height: height)
}
}
class myCarouselFlowLayout: UICollectionViewFlowLayout,UICollectionViewDelegateFlowLayout {
private let fadeFactor: CGFloat = 0.5
override var collectionViewContentSize: CGSize {
super.collectionViewContentSize
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
super.layoutAttributesForElements(in: rect)?.map {
self.layoutAttributesForItem(at: $0.indexPath)!
}
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let superValue = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else { return nil }
guard let cv = collectionView else { return nil }
let collectionMidPoint = CGPoint(x: cv.bounds.midX, y: cv.bounds.midY)
let itemMidPoint = superValue.center
let distance = abs(itemMidPoint.x - collectionMidPoint.x)
if distance > 100 {
UIView.animate(withDuration: 0.2) {
superValue.alpha = self.fadeFactor
superValue.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
cv.layoutIfNeeded()
}
}
return superValue
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
true
}
var velocityThresholdPerPage: CGFloat = 2
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
guard let collectionView = collectionView else { return proposedContentOffset }
let pageLength: CGFloat
let approxPage: CGFloat
let currentPage: CGFloat
pageLength = (self.itemSize.width + self.minimumLineSpacing)
approxPage = collectionView.contentOffset.x / pageLength
currentPage = round(approxPage)
if velocity.x == 0 {
return CGPoint(x: currentPage * pageLength, y: 0)
}
var nextPage: CGFloat = currentPage + (velocity.x > 0 ? 1 : -1)
let increment = velocity.x / velocityThresholdPerPage
nextPage += round(increment)
return CGPoint(x: nextPage * pageLength, y: 0)
}
Please give me some advice on where and how should I use animations on it? Should I do it with UIView.animate or something else? I know that I need to use layoutIfNeeded() to animate constraints, but it doesn't work with it.

UICollectionView Cell Custom FlowLayout Breaks When New Post is Added on Top

Description:
I have been working on an app which displays images and caption in a CollectionView. I have made a custom Cell and CustomFlowLayout for the cell where the width of the cell, image and caption is equal to width of screen and height will change according to aspect ratio of the image height and height needed for the caption. The images which are displayed are stored on FirebaseStorage and I have also saved imagewidth and imageheight in firebaseDatabase. I Use SD_Web images to load and cache images. When the app loads for the first time the layout works perfectly fine as expected. The cells are arranged according to image height and caption height , with images being in aspect ratio.
The main problem occurs when a new post is done. I insert new post on the top of collectionview, and when the post is received the layout breaks, images becomes messed up, the caption goes on top image, lot of white space between image or caption. when I terminate the app from background and run it again , this time the layout is perfectly fine with new post present. I have to terminate app after everyone post to make the layout work.
What I feel the problem is, when I post the image. The new post is added on the top cell and the item on top cell pushed below without having the old height. how can I take this problem. I tried searching a lot but still of no use.
PS:
Using Autolayout for cell in IB.
FactsFeverLayout Class
import UIKit
protocol FactsFeverLayoutDelegate: class {
func collectionView(CollectionView: UICollectionView, heightForThePhotoAt indexPath: IndexPath, with width: CGFloat) -> CGFloat
func collectionView(CollectionView: UICollectionView, heightForCaptionAt indexPath: IndexPath, with width: CGFloat) -> CGFloat
}
class FactsFeverLayout: UICollectionViewLayout {
var cellPadding : CGFloat = 5.0
var delegate: FactsFeverLayoutDelegate?
private var contentHeight : CGFloat = 0.0
private var contentWidth : CGFloat {
let insets = collectionView!.contentInset
return (collectionView!.bounds.width - insets.left + insets.right)
}
private var attributeCache = [FactsFeverLayoutAttributes]()
override func prepare() {
if attributeCache.isEmpty {
let containerWidth = contentWidth
var xOffset : CGFloat = 0
var yOffset : CGFloat = 0
for item in 0 ..< collectionView!.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let width = containerWidth - cellPadding * 2
let photoHeight:CGFloat = (delegate?.collectionView(CollectionView: collectionView!, heightForThePhotoAt: indexPath, with: width))!
let captionHeight: CGFloat = (delegate?.collectionView(CollectionView: collectionView!, heightForCaptionAt: indexPath, with: width))!
let height: CGFloat = cellPadding + photoHeight + captionHeight + cellPadding
let frame = CGRect(x: xOffset, y: yOffset, width: containerWidth, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
// Create CEll Layout Atributes
let attributes = FactsFeverLayoutAttributes(forCellWith: indexPath)
attributes.photoHeight = photoHeight
attributes.frame = insetFrame
attributeCache.append(attributes)
// Update The Colunm any Y axis
contentHeight = max(contentHeight, frame.maxY)
yOffset = yOffset + height
}
}
}
override var collectionViewContentSize: CGSize{
return CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in attributeCache {
if attributes.frame.intersects(rect){
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
}
// UICollectionView FlowLayout
// Abstract
class FactsFeverLayoutAttributes: UICollectionViewLayoutAttributes {
var photoHeight : CGFloat = 0.0
override func copy(with zone: NSZone? = nil) -> Any {
let copy = super.copy(with: zone) as! FactsFeverLayoutAttributes
copy.photoHeight = photoHeight
return copy
}
override func isEqual(_ object: Any?) -> Bool {
if let attributes = object as? FactsFeverLayoutAttributes {
if attributes.photoHeight == photoHeight {
super.isEqual(object)
}
}
return false
}
}
CollectionViewCell Class
class NewCellCollectionViewCell: UICollectionViewCell {
var facts: Facts!
var currentUser = Auth.auth().currentUser?.uid
// IBOutlets
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var likeLable: UILabel!
#IBOutlet weak var likeButton: UIButton!
#IBOutlet weak var infoButton: UIButton!
#IBOutlet weak var buttonView: UIView!
#IBOutlet weak var captionTextView: UITextView!
override func awakeFromNib() {
super.awakeFromNib()
likeButton.setImage(UIImage(named: "noLike"), for: .normal)
likeButton.setImage(UIImage(named: "like"), for: .selected)
setupLayout()
}
func configureCell(fact: Facts){
facts = fact
imageView.sd_setImage(with: URL(string: fact.factsLink))
likeLable.text = String(fact.factsLikes.count)
captionTextView.text = fact.captionText
let factsRef = Database.database().reference().child("Facts").child(facts.factsId).child("likes")
factsRef.observeSingleEvent(of: .value) { (snapshot) in
if fact.factsLikes.contains(self.currentUser!){
self.likeButton.isSelected = true
} else {
self.likeButton.isSelected = false
}
}
}
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
if let attributes = layoutAttributes as? FactsFeverLayoutAttributes {
imageHeightConstraint.constant = attributes.photoHeight
}
}
}
ViewController Class
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//MARK: Outlets
#IBOutlet weak var uploadButtonOutlet: UIBarButtonItem!
#IBOutlet weak var collectionView: UICollectionView!
//MARK:- Properties
var images: [UIImage] = []
var factsArray:[Facts] = [Facts]()
var likeUsers:[String] = []
let currentUser = Auth.auth().currentUser?.uid
private let refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if #available(iOS 10.0, *) {
collectionView.refreshControl = refreshControl
} else {
collectionView.addSubview(refreshControl)
}
refreshControl.addTarget(self, action: #selector(refreshView), for: .valueChanged)
refreshControl.tintColor = UIColor.white
if let layout = collectionView?.collectionViewLayout as? FactsFeverLayout {
layout.delegate = self
}
collectionView.backgroundColor = UIColor.black
observeFactsFromFirebase()
}
#objc func refreshView(){
observeFactsFromFirebase()
}
//MARK:- Upload Facts
#IBAction func uploadButtonPressed(_ sender: Any) {
self.selectPhoto()
(deleted the function of selectPhoto but it works, UIImagePicker is used)
}
private func uploadImageToFirebaseStorage(image: UIImage, completion: #escaping (_ imageUrl: String) -> ()){
let imageName = NSUUID().uuidString + ".jpg"
let ref = Storage.storage().reference().child("message_images").child(imageName)
if let uploadData = image.jpegData(compressionQuality: 0.2){
ref.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(" Failed to upload Image", error)
}
ref.downloadURL(completion: { (url, err) in
if let err = err {
print("Unable to upload image into storage due to \(err)")
}
let messageImageURL = url?.absoluteString
completion(messageImageURL!)
})
})
}
}
func addToDatabase(imageUrl:String, caption: String, image: UIImage){
let Id = NSUUID().uuidString
likeUsers.append(currentUser!)
let timeStamp = NSNumber(value: Int(NSDate().timeIntervalSince1970))
let factsDB = Database.database().reference().child("Facts")
let factsDictionary = ["factsLink": imageUrl, "likes": likeUsers, "factsId": Id, "timeStamp": timeStamp, "captionText": caption, "imageWidth": image.size.width, "imageHeight": image.size.height] as [String : Any]
factsDB.child(Id).setValue(factsDictionary){
(error, reference) in
if error != nil {
print(error)
ProgressHUD.showError("Image Upload Failed")
self.uploadButtonOutlet.isEnabled = true
return
} else{
print("Message Saved In DB")
ProgressHUD.showSuccess("image Uploded Successfully")
self.uploadButtonOutlet.isEnabled = true
self.observeFactsFromFirebase()
}
}
}
var imageUrl: [String] = []
func observeFactsFromFirebase(){
let factsDB = Database.database().reference().child("Facts").queryOrdered(byChild: "timeStamp")
factsDB.observe(.value){ (snapshot) in
print("Observer Data snapshot \(snapshot.value)")
self.factsArray = []
self.imageUrl = []
self.likeUsers = []
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshot {
if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
let id = snap.key
let facts = Facts(dictionary: postDictionary)
self.factsArray.insert(facts, at: 0)
self.imageUrl.insert(facts.factsLink, at: 0)
}
}
}
self.collectionView.reloadData()
self.refreshControl.endRefreshing()
}
collectionView.reloadData()
}
// Download Image From Database
//-> Here I download image from firebase and store it locally and append it to images array (Deleted the code to remove unwanted clutter)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MARK: Data Source
extension ViewController: UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return factsArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let facts = factsArray[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newCellTrial", for: indexPath) as? NewCellCollectionViewCell
cell?.configureCell(fact: facts)
cell?.infoButton.addTarget(self, action: #selector(reportButtonPressed), for: .touchUpInside)
return cell!
}
}
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
let photos = IDMPhoto.photos(withURLs: imageUrl)
let browser = IDMPhotoBrowser(photos: photos)
browser?.setInitialPageIndex(UInt(indexPath.row))
self.present(browser!, animated: true, completion: nil)
}
}
extension ViewController: FactsFeverLayoutDelegate {
func collectionView(CollectionView: UICollectionView, heightForThePhotoAt indexPath: IndexPath, with width: CGFloat) -> CGFloat {
let facts = factsArray[indexPath.item]
let imageSize = CGSize(width: CGFloat(facts.imageWidht), height: CGFloat(facts.imageHeight))
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let rect = AVMakeRect(aspectRatio: imageSize, insideRect: boundingRect)
return rect.size.height
}
func collectionView(CollectionView: UICollectionView, heightForCaptionAt indexPath: IndexPath, with width: CGFloat) -> CGFloat {
let fact = factsArray[indexPath.item]
let topPadding = CGFloat(8)
let bottomPadding = CGFloat(8)
let captionFont = UIFont.systemFont(ofSize: 15)
let viewHeight = CGFloat(40) //-> There is view below caption which holds like button and info button its height is constant (40)
let captionHeight = self.height(for: fact.captionText, with: captionFont, width: width)
let height = topPadding + captionHeight + topPadding + viewHeight + bottomPadding + topPadding + 10
return height
}
func height(for text: String, with font: UIFont, width: CGFloat) -> CGFloat {
let nsstring = NSString(string: text)
let maxHeight = CGFloat(1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let textAttributes = [NSAttributedString.Key.font: font]
let boundingRect = nsstring.boundingRect(with: CGSize(width: width, height: maxHeight), options: options, attributes: textAttributes, context: nil)
return ceil(boundingRect.height)
}
}
as you have used attributeCache, layoutAttribute of First Cell is Already Stored in cache.when you add images at first place and reload your collectionView , old Attribute for First cell will be retired from Cache and applying to your collectionView layout.
so you have to remove Element From Cache before reloading
override func prepare() {
attributeCache.RemoveAll()
if attributeCache.isEmpty {
let containerWidth = contentWidth
var xOffset : CGFloat = 0
var yOffset : CGFloat = 0
for item in 0 ..< collectionView!.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let width = containerWidth - cellPadding * 2
let photoHeight:CGFloat = (delegate?.collectionView(CollectionView: collectionView!, heightForThePhotoAt: indexPath, with: width))!
let captionHeight: CGFloat = (delegate?.collectionView(CollectionView: collectionView!, heightForCaptionAt: indexPath, with: width))!
let height: CGFloat = cellPadding + photoHeight + captionHeight + cellPadding
let frame = CGRect(x: xOffset, y: yOffset, width: containerWidth, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
// Create CEll Layout Atributes
let attributes = FactsFeverLayoutAttributes(forCellWith: indexPath)
attributes.photoHeight = photoHeight
attributes.frame = insetFrame
attributeCache.append(attributes)
// Update The Colunm any Y axis
contentHeight = max(contentHeight, frame.maxY)
yOffset = yOffset + height
}
}
}

How to trigger pagination from all sides using scroll and border elements position of collection view?

I've created custom collection view layout(for MultiDirectional scroll), running successfully. Now, I tried to achieve pagination from all sides (top, left, right and bottom). For that, I am tracing the scroll direction and upon reaching the border elements, I wish to paginate(load more data) in that direction. But as I need to place the page default to top-left position, the top-left elements are already reached and hence resulting in conflicts. Can you help?
Following code I tried:
import UIKit
class ViewController: UIViewController{
var cellId: String = "MyCellId"
var vPivotPrev = 0
var vPivotNext = 19
var hPivotPrev = 0
var hPivotNext = 29
var targetPoint = CGPoint(x: 0, y: 0)
var scrollDirection: String = ""
var scrolledDailyToTop:String = ""
var scrolledDailyToBottom:String = ""
var scrolledDailyToLeft:String = ""
var scrolledDailyToRight:String = ""
var shouldPaginate:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
showCollectionView()
}
var customCollectionView: UICollectionView = { // CODE TO CREATE CUSTOM COLLECTION VIEW
let layout = CustomCollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
return cv
}()
class CustomCell: UICollectionViewCell{ // CODE TO CREATE CUSTOM CELLS
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
let label: UILabel = {
let myLabel = UILabel()
return myLabel
}()
func setup(){
addSubview(label)
}
}
func showCollectionView(){
view.addSubview(customCollectionView)
customCollectionView.backgroundColor = .darkGray
customCollectionView.frame = CGRect(x: 60, y: 145, width: UIScreen.main.bounds.size.width-120, height: UIScreen.main.bounds.size.height/1.8)
customCollectionView.dataSource = self
customCollectionView.delegate = self
customCollectionView.register(CustomCell.self, forCellWithReuseIdentifier: cellId) // REGISTER CELL CLASS
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// DETECT SCROLL DIRECTION CODE
var currentPoint = scrollView.contentOffset
if(targetPoint.y > currentPoint.y){
scrollDirection = "going up"
print(scrollDirection)
}
else if(targetPoint.y < currentPoint.y){
scrollDirection = "going down"
print(scrollDirection)
}
if(targetPoint.x > currentPoint.x){
scrollDirection = "going left"
print(scrollDirection)
}
else if(targetPoint.x < currentPoint.x){
scrollDirection = "going right"
print(scrollDirection)
}
self.targetPoint = scrollView.contentOffset
}
}
extension ViewController: UICollectionViewDataSource{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
cell.label.text = "\(indexPath.section.description),\(indexPath.item.description)"
cell.backgroundColor = .lightGray
cell.label.frame = CGRect(x: 0, y: 0, width: cell.contentView.bounds.width, height: 10)
cell.label.textColor = .white
cell.bringSubview(toFront: cell.label)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
for visibleIndices in collectionView.indexPathsForVisibleItems{
if(visibleIndices.section == vPivotPrev){
scrolledDailyToTop = "top"
shouldPaginate = true
paginate()
}
else if(visibleIndices.section == vPivotNext){
scrolledDailyToBottom = "bottom"
shouldPaginate = true
paginate()
}
else if(visibleIndices.item == hPivotPrev){
scrolledDailyToLeft = "left"
shouldPaginate = true
paginate()
}
else if(visibleIndices.item == hPivotNext){
scrolledDailyToRight = "right"
shouldPaginate = true
paginate()
}
}
}
func paginate(){
print("Swipe Direction: \(scrollDirection)")
if(shouldPaginate == true){
if(self.scrollDirection == "going down" && self.scrolledDailyToTop == "top"){ // PAGINATING USING 9 BOX LOGIC
print("Fetch Vertical previous page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .bottom, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: false)
shouldPaginate = false
}
else if(self.scrollDirection == "going up" && self.scrolledDailyToBottom == "bottom"){
print("Fetch Vertical next page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: false)
shouldPaginate = false
}
else if(self.scrollDirection == "going right" && self.scrolledDailyToLeft == "left"){
print("Fetch Horizontal previous page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .right, animated: false)
shouldPaginate = false
}
else if(self.scrollDirection == "going left" && self.scrolledDailyToRight == "right"){
print("Fetch Horizontal next page")
//getNewPageData(gotopageURL: self.goToPageURL)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
self.customCollectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: false)
shouldPaginate = false
}
scrolledDailyToTop = ""
scrolledDailyToBottom = ""
scrolledDailyToLeft = ""
scrolledDailyToRight = ""
}
}
}
extension ViewController: UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
let cell:CustomCell = collectionView.cellForItem(at: indexPath)! as! ViewController.CustomCell
print("SELECTED CELL: \(cell.label.text!)")
return true
}
}
The code for Multi-Directional Scroll CustomCollectionViewLayout
import UIKit
class CustomCollectionViewLayout:UICollectionViewFlowLayout {
let CELL_HEIGHT = 50.0
let CELL_WIDTH = 80.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var cellAttrsDictionary = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
var contentSize = CGSize.zero
var dataSourceDidUpdate = true
override var collectionViewContentSize : CGSize {
return self.contentSize
}
override func prepare() {
dataSourceDidUpdate = false
cellAttrsDictionary.removeAll()
if let sectionCount = collectionView?.numberOfSections, sectionCount > 0 {
for section in 0...sectionCount-1 {
if let rowCount = collectionView?.numberOfItems(inSection: section), rowCount > 0 {
for item in 0...rowCount-1 {
let cellIndex = IndexPath(item: item, section: section)
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}
cellAttrsDictionary[cellIndex] = cellAttributes
}
}
}
}
let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in cellAttrsDictionary.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath]!
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}

iOS: in Swift3, in my collectionView, when I scroll downstair, the collectionView comes automatically at the top. How to stop it?

I would like my collectionView to stop in the cell. The problem is that when I scroll downstair, if I release it, it comes automatically at the first position...
I tried with collection.alwaysBounceVertical = true without success...
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
let layout = OrganiserLayout()
let frameCollection = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.width, height: self.view.frame.height + 1000)
let collection = UICollectionView(frame: frameCollection, collectionViewLayout: layout)
collection.delegate = self
collection.dataSource = self
collection.backgroundColor = UIColor.white
collection.register(OrganiserCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.view.addSubview(collection)
collection.alwaysBounceVertical = true
collection.alwaysBounceHorizontal = true
collection.bounces = true
collection.isPagingEnabled = false
collection.isScrollEnabled = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return 40
}
}
class OrganiserLayout:UICollectionViewLayout {
let cellWidth:CGFloat = 100
var attrDict = Dictionary<IndexPath,UICollectionViewLayoutAttributes>()
var contentSize = CGSize.zero
override var collectionViewContentSize : CGSize {
return self.contentSize
}
override func prepare() {
// Generate the attributes for each cell based on the size of the collection view and our chosen cell width
if let cv = collectionView {
let collectionViewHeight = cv.frame.height
let numberOfSections = cv.numberOfSections
self.contentSize = cv.frame.size
self.contentSize.width = cellWidth*CGFloat(numberOfSections)
for section in 0...numberOfSections-1 {
let numberOfItemsInSection = cv.numberOfItems(inSection: section)
let itemHeight = collectionViewHeight/CGFloat(numberOfItemsInSection)
let itemXPos = cellWidth*CGFloat(section)
for item in 0...numberOfItemsInSection-1 {
let indexPath = IndexPath(item: item, section: section)
let itemYPos = itemHeight*CGFloat(item)
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attr.frame = CGRect(x: itemXPos, y: itemYPos, width: cellWidth, height: itemHeight)
attrDict[indexPath] = attr
}
}
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Here we return the layout attributes for cells in the current rectangle
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in attrDict.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// Here we return one attribute object for the specified indexPath
return attrDict[indexPath]!
}
}
class OrganiserCollectionViewCell:UICollectionViewCell {
var label:UILabel!
var seperator:UIView!
override init(frame: CGRect) {
super.init(frame: frame)
label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(label)
seperator = UIView()
seperator.backgroundColor = UIColor.black
seperator.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(seperator)
let views:[String:UIView] = [
"label":label,
"sep":seperator
]
let cons = [
"V:|-20-[label]",
"V:[sep(1)]|",
"H:|[label]|",
"H:|[sep]|"
]
for con in cons {
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: con, options: [], metrics: nil, views: views))
}
}
I need that because I need the user stops on the cell, and click on it. With that problem, he cannot click on the cells that are downstairs.
Thanks in advance.
Set some height for contentSize like below :
self.contentSize.height = CGFloat(2750)
In your code :
class OrganiserLayout:UICollectionViewLayout {
override func prepare() {
// Generate the attributes for each cell based on the size of the collection view and our chosen cell width
if let cv = collectionView {
let collectionViewHeight = cv.frame.height
let numberOfSections = cv.numberOfSections
self.contentSize = cv.frame.size
self.contentSize.width = cellWidth*CGFloat(numberOfSections)
self.contentSize.height = CGFloat(2750) // I added this line
for section in 0...numberOfSections-1 {
let numberOfItemsInSection = cv.numberOfItems(inSection: section)
let itemHeight = collectionViewHeight/CGFloat(numberOfItemsInSection)
let itemXPos = cellWidth*CGFloat(section)
for item in 0...numberOfItemsInSection-1 {
let indexPath = IndexPath(item: item, section: section)
let itemYPos = itemHeight*CGFloat(item)
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attr.frame = CGRect(x: itemXPos, y: itemYPos, width: cellWidth, height: itemHeight)
attrDict[indexPath] = attr
}
}
}
}
}

Collection views cells are not appearing in collection view?

This is my first time working with collection views and I am struggling quite a bit. I set up a collection view layout in the "setupView" function, and then implemented the typical view methods, like numberOfSections and cellForRowAtIndexPath. Right now, I'm just trying to get the collection view to work so I'm just using an image that I already have in my workspace, instead of getting pictures from an API (that will come later).
Here is the code I am using. Why is it not displaying anything other than a black screen ?
import UIKit
import Alamofire
import AlamofireImage
class PhotoBrowserCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let goldenWordsYellow = UIColor(red: 247.00/255.0, green: 192.00/255.0, blue: 51.00/255.0, alpha: 0.5)
#IBOutlet weak var menuButton:UIBarButtonItem!
#IBOutlet var picturesCollectionView: UICollectionView!
var pictureObjects = NSMutableOrderedSet(capacity: 1000)
var customRefreshControl = UIRefreshControl()
let PhotoBrowserCellIdentifier = "PhotoBrowserCell"
var dateFormatter = NSDateFormatter()
var nodeIDArray = NSMutableArray()
var timeStampDateString : String!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(PhotoBrowserCollectionViewCell.self, forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
self.revealViewController().rearViewRevealWidth = 280
collectionView!.delegate = self
collectionView!.dataSource = self
customRefreshControl = UIRefreshControl()
customRefreshControl.backgroundColor = goldenWordsYellow
customRefreshControl.tintColor = UIColor.whiteColor()
self.picturesCollectionView!.addSubview(customRefreshControl)
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.title = "Pictures"
setupView()
populatePhotos()
self.dateFormatter.dateFormat = "dd/MM/yy"
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5 // setting an arbitrary value in case pictureObjects is not getting correctly populated
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserCellIdentifier, forIndexPath: indexPath) as! PhotoBrowserCollectionViewCell
cell.imageView.image = UIImage(named: "mail")
return cell
}
And here is my setupView function.
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("ShowPhoto", sender: (self.pictureObjects.objectAtIndex(indexPath.item) as! PictureElement).imageURL)
}
func setupView() {
navigationController?.setNavigationBarHidden(false, animated: true)
let layout = UICollectionViewFlowLayout()
let itemWidth = (view.bounds.size.width - 2) / 3
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 1.0
layout.minimumLineSpacing = 1.0
collectionView!.collectionViewLayout = layout
navigationItem.title = "Pictures"
customRefreshControl.tintColor = UIColor.whiteColor()
customRefreshControl.addTarget(self, action: "handleRefresh", forControlEvents: .ValueChanged)
self.collectionView!.addSubview(customRefreshControl)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(120, 120)
}
Everything looks really messed up in the storyboard. I'm using a UICollectionViewController swift class (not a UIViewController + collectionView combo), and I don't really know which outlets I should be using. Here is my list of connections on the entire view controller:
And finally, here is my very simple view hierarchy.
I truly have no idea why the collection view isn't working properly. Any ideas ?
EDIT 1: I changed a lot of code and ended up getting my collectionView to work. For those who are struggling with a similar issue, here is the entirety of the code I am using for the collectionView. Maybe it will help you fix problems in your own collectionView code
import UIKit
import Alamofire
import AlamofireImage
class PhotoBrowserCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let goldenWordsYellow = UIColor(red: 247.00/255.0, green: 192.00/255.0, blue: 51.00/255.0, alpha: 0.5)
#IBOutlet weak var menuButton:UIBarButtonItem!
#IBOutlet var picturesCollectionView: UICollectionView!
var temporaryPictureObjects = NSMutableOrderedSet(capacity: 1000)
var pictureObjects = NSMutableOrderedSet(capacity: 1000)
var goldenWordsRefreshControl = UIRefreshControl()
var revealViewControllerIndicator : Int = 0
let imageCache = NSCache()
var customView: UIView!
var labelsArray: [UILabel] = []
var isAnimating = false
var currentColorIndex = 0
var currentLabelIndex = 0
var timer : NSTimer!
var populatingPhotos = false
var currentPage = 0
let PhotoBrowserCellIdentifier = "PhotoBrowserCell"
var dateFormatter = NSDateFormatter()
var nodeIDArray = NSMutableArray()
var timeStampDateString : String!
var cellLoadingIndicator = UIActivityIndicatorView()
var scrollViewDidScrollLoadingIndicator = UIActivityIndicatorView()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(PhotoBrowserCollectionViewCell.self, forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
self.cellLoadingIndicator.backgroundColor = goldenWordsYellow
self.cellLoadingIndicator.hidesWhenStopped = true
if self.revealViewController() != nil {
revealViewControllerIndicator = 1
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
self.revealViewController().rearViewRevealWidth = 280
collectionView!.delegate = self
collectionView!.dataSource = self
goldenWordsRefreshControl = UIRefreshControl()
goldenWordsRefreshControl.backgroundColor = goldenWordsYellow
goldenWordsRefreshControl.tintColor = UIColor.whiteColor()
self.collectionView!.addSubview(goldenWordsRefreshControl)
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.title = "Pictures"
setupView()
populatePhotos()
self.dateFormatter.dateFormat = "dd/MM/yy"
self.cellLoadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
self.cellLoadingIndicator.color = goldenWordsYellow
self.cellLoadingIndicator.center = (self.collectionView?.center)!
self.collectionView!.addSubview(cellLoadingIndicator)
self.collectionView!.bringSubviewToFront(cellLoadingIndicator)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if goldenWordsRefreshControl.refreshing {
if !isAnimating {
holdRefreshControl()
}
}
}
func holdRefreshControl() {
timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "handleRefresh", userInfo: nil, repeats: true)
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (pictureObjects.count) // setting an arbitrary value in case pictureObjects is not getting correctly populated
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserCellIdentifier, forIndexPath: indexPath) as! PhotoBrowserCollectionViewCell
if let pictureObject = pictureObjects.objectAtIndex(indexPath.row) as? PictureElement {
let title = pictureObject.title ?? "" // if pictureObject.title == nil, then we return an empty string
let timeStampDateObject = NSDate(timeIntervalSince1970: NSTimeInterval(pictureObject.timeStamp))
let timeStampDateString = dateFormatter.stringFromDate(timeStampDateObject)
let author = pictureObject.author ?? ""
let issueNumber = pictureObject.issueNumber ?? ""
let volumeNumber = pictureObject.volumeNumber ?? ""
let nodeID = pictureObject.nodeID ?? 0
let imageURL = pictureObject.imageURL ?? "http://goldenwords.ca/sites/all/themes/custom/gw/logo.png"
cell.request?.cancel()
if let image = self.imageCache.objectForKey(imageURL) as? UIImage {
cell.imageView.image = image
} else {
cell.imageView.image = nil
cell.request = Alamofire.request(.GET, imageURL).responseImage() { response in
if let image = response.result.value {
self.imageCache.setObject(response.result.value!, forKey: imageURL)
if cell.imageView.image == nil {
cell.imageView.image = image
}
}
}
}
}
return cell
}
self.performSegueWithIdentifier("ShowPhoto", sender: self)
}
func setupView() {
navigationController?.setNavigationBarHidden(false, animated: true)
let layout = UICollectionViewFlowLayout()
let itemWidth = (view.bounds.size.width) / 3
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 1.0
layout.minimumLineSpacing = 1.0
collectionView!.collectionViewLayout = layout
navigationItem.title = "Pictures"
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(((self.collectionView?.frame.width)!*0.5)-2, self.collectionView!.frame.height/3)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowPhoto" {
let detailViewController = segue.destinationViewController as! PhotoViewerViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()
let indexPath = indexPaths![0] as! NSIndexPath
let item = indexPath.item
}
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
if (scrollView.contentOffset.y + view.frame.size.height > scrollView.contentSize.height * 0.75) {
populatePhotos()
}
}
func populatePhotos() {
if populatingPhotos {
return
}
populatingPhotos = true
self.cellLoadingIndicator.startAnimating()
self.temporaryPictureObjects.removeAllObjects()
Alamofire.request(GWNetworking.Router.Pictures(self.currentPage)).responseJSON() { response in
if let JSON = response.result.value {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)) {
var nodeIDArray : [Int]
if (JSON .isKindOfClass(NSDictionary)) {
for node in JSON as! Dictionary<String, AnyObject> {
let nodeIDValue = node.0
var lastItem : Int = 0
self.nodeIDArray.addObject(nodeIDValue)
if let pictureElement : PictureElement = PictureElement(title: "Picture", nodeID: 0, timeStamp: 0, imageURL: "http://goldenwords.ca/sites/all/themes/custom/gw/logo.png", author: "Staff", issueNumber: "Issue # error", volumeNumber: "Volume # error") {
pictureElement.title = node.1["title"] as! String
pictureElement.nodeID = Int(nodeIDValue)!
let timeStampString = node.1["revision_timestamp"] as! String
pictureElement.timeStamp = Int(timeStampString)!
if let imageURL = node.1["image_url"] as? String {
pictureElement.imageURL = imageURL
}
if let author = node.1["author"] as? String {
pictureElement.author = author
}
if let issueNumber = node.1["issue_int"] as? String {
pictureElement.issueNumber = issueNumber
}
if let volumeNumber = node.1["volume_int"] as? String {
pictureElement.volumeNumber = volumeNumber
}
if self.pictureObjects.containsObject(pictureElement) {
// do not add the pictureElement to the set of pictures
} else {
lastItem = self.temporaryPictureObjects.count // Using a temporary set to not handle the dataSource set directly (safer).
self.temporaryPictureObjects.addObject(pictureElement)
}
let indexPaths = (lastItem..<self.temporaryPictureObjects.count).map { NSIndexPath(forItem: $0, inSection: 0) }
}
}
let timeStampSortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
self.temporaryPictureObjects.sortUsingDescriptors([timeStampSortDescriptor])
}
dispatch_async(dispatch_get_main_queue()) {
for object in self.temporaryPictureObjects {
self.pictureObjects.addObject(object)
}
self.temporaryPictureObjects.removeAllObjects()
self.collectionView!.reloadData()
self.cellLoadingIndicator.stopAnimating()
self.goldenWordsRefreshControl.endRefreshing()
self.currentPage++
self.populatingPhotos = false
}
}
}
}
}
func handleRefresh() {
goldenWordsRefreshControl.beginRefreshing()
self.pictureObjects.removeAllObjects()
self.temporaryPictureObjects.removeAllObjects()
self.collectionView!.reloadData()
self.currentPage = 0
self.picturesCollectionView.bringSubviewToFront(cellLoadingIndicator)
self.populatingPhotos = false
populatePhotos()
}
}
Simply reload your collectionView after the data is formatted.
picturesCollectionView.reloadData()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(PhotoBrowserCollectionViewCell.self, forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
self.revealViewController().rearViewRevealWidth = 280
collectionView!.delegate = self
collectionView!.dataSource = self
customRefreshControl = UIRefreshControl()
customRefreshControl.backgroundColor = goldenWordsYellow
customRefreshControl.tintColor = UIColor.whiteColor()
self.picturesCollectionView!.addSubview(customRefreshControl)
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.title = "Pictures"
setupView()
populatePhotos()
self.dateFormatter.dateFormat = "dd/MM/yy"
picturesCollectionView.reloadData()
}

Resources