import UIKit
class HomePageCell: UICollectionViewCell {
#IBOutlet private weak var containerView: UIView!
#IBOutlet weak var photos: UIImageView!
#IBOutlet weak var songname: UILabel!
#IBOutlet weak var songmaker: UILabel!
//#IBOutlet weak var pfppic: UIImageView!
#IBOutlet weak var viewcount: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
containerView.layer.cornerRadius = 6
containerView.layer.masksToBounds = true
}
var photo: Photo? {
didSet {
if let photo = photo {
photos.image = photo.image
songname.text = photo.name
songmaker.text = photo.makername
viewcount.text = photo.likecount
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
self.photos.image = nil
}
}
import UIKit
protocol PinterestLayoutDelegate: AnyObject {
func collectionView(
_ collectionView: UICollectionView,
heightForPhotoAtIndexPath indexPath: IndexPath) -> CGFloat
}
class PinterestLayout: UICollectionViewLayout {
// 1
weak var delegate: PinterestLayoutDelegate?
// 2
private let numberOfColumns = 2
private let cellPadding: CGFloat = 6
// 3
private var cache: [UICollectionViewLayoutAttributes] = []
// 4
private var contentHeight: CGFloat = 0
private var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
// 5
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
// 1
guard
cache.isEmpty,
let collectionView = collectionView
else {
return
}
// 2
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset: [CGFloat] = []
for column in 0..<numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset: [CGFloat] = .init(repeating: 0, count: numberOfColumns)
// 3
for item in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
// 4
let photoHeight = delegate?.collectionView(
collectionView,
heightForPhotoAtIndexPath: indexPath) ?? 180
let height = cellPadding * 2 + photoHeight
let frame = CGRect(x: xOffset[column],
y: yOffset[column],
width: columnWidth,
height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
// 5
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
// 6
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
}
override func layoutAttributesForElements(in rect: CGRect)
-> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath)
-> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
}
extension HomePageViewController: PinterestLayoutDelegate {
func collectionView(
_ collectionView: UICollectionView,
heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat {
return photos[indexPath.item].image.size.height
}
}
import UIKit
struct Photo {
var image: UIImage
var name: String
var makername: String
var likecount: String
init(image: UIImage, name: String, makername: String, likecount: String) {
self.image = image
self.name = name
self.makername = makername
self.likecount = likecount
}
init?(dictionary: [String: String]) {
guard
let name = dictionary["Name"],
let makername = dictionary["Makername"],
let photo = dictionary["Photo"],
let likecount = dictionary["Likecount"],
let image = UIImage(named: photo)
else {
return nil
}
self.init(image: image, name: name, makername: makername, likecount: likecount)
}
static func allPhotos() -> [Photo] {
var photos: [Photo] = []
guard
let URL = Bundle.main.url(forResource: "Photos", withExtension: "plist"),
let photosFromPlist = NSArray(contentsOf: URL) as? [[String:String]]
else {
return photos
}
for dictionary in photosFromPlist {
if let photo = Photo(dictionary: dictionary) {
photos.append(photo)
}
}
return photos
}
}
import UIKit
final class HomePageViewController: UICollectionViewController {
// MARK: - Properties
var photos = Photo.allPhotos()
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView?.collectionViewLayout as? PinterestLayout {
layout.delegate = self
}
self.collectionView.backgroundColor = .white
self.collectionView.dataSource = self
self.collectionView.delegate = self
let iconImage = UIImage(named: "name")
let imageView = UIImageView(image: iconImage)
self.navigationItem.titleView = imageView
}
private let sectionInsets2 = UIEdgeInsets(
top: 50.0,
left: 20.0,
bottom: 50.0,
right: 20.0)
private let itemsPerRow: CGFloat = 1
private let itemsPerRow1: CGFloat = 1
private let itemsPerRow2: CGFloat = 2
// MARK: - Private
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 1
} else if section == 1 {
return 1
} else {
return photos.count
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomePageHeaderCell", for: indexPath) as! HomePageHeaderCell
return cell
} else if indexPath.section == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomePageProfileBar", for: indexPath) as! HomePageProfileBar
return cell
} else if indexPath.section == 2 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomePageCell", for: indexPath) as! HomePageCell
cell.photo = photos[indexPath.item]
//cell.pfppic.image = UIImage(named: "pfppic")
//cell.pfppic.layer.cornerRadius = 15.0
return cell
}
return UICollectionViewCell()
}
}
extension HomePageViewController: UICollectionViewDelegateFlowLayout {
// 1
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// 2H
if indexPath.section == 0 {
let paddingSpace = 0 * (itemsPerRow + 1)
let availableWidth = view.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: 50)
} else if indexPath.section == 1 {
let paddingSpace1 = 0 * (itemsPerRow1 + 1)
let availableWidth1 = view.frame.width - paddingSpace1
let widthPerItem1 = availableWidth1 / itemsPerRow1
return CGSize(width: widthPerItem1, height: 100)
} else {
let paddingSpace2 = sectionInsets2.left * (itemsPerRow2 + 1)
let availableWidth2 = view.frame.width - paddingSpace2
let widthPerItem2 = availableWidth2 / itemsPerRow2
return CGSize(width: widthPerItem2, height: widthPerItem2)
}
}
// 3
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets2
}
// 4
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets2.left
}
}
I have the array built and I don't know why any pictures won't show
Related
Let's say we have CollectionViewController with Cells
So, my goal is to send the data from the active CollectionViewControllerCell (let's say i want to pass the category name) to another controller after click action on that CELL. So, how can i pass data from
import UIKit
class CategoriesViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var activeCategoryItemTitle:String = ""
var categories = Category.fetchCategories()
let cellScale: CGFloat = 0.7
override func viewDidLoad() {
super.viewDidLoad()
let screenSize = UIScreen.main.bounds.size
let cellWidth = floor(screenSize.width * cellScale)
let cellHeight = floor(screenSize.height * cellScale)
let insetX = (view.bounds.width - cellWidth) / 2
let insetY = (view.bounds.height - cellHeight) / 2
let layout = collectionView!.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width:cellWidth,height:cellHeight)
// collectionView.contentInset = UIEdgeInsets(top:insetY,left:insetX,bottom:insetY,right:insetX)
print(insetY)
collectionView.dataSource = self
collectionView.delegate = self
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC: ProductsViewController = segue.destination as! ProductsViewController
destinationVC.titleOfCategory = self.activeCategoryItemTitle
// let product = ProductsViewController()
// product.titleOfCategory = "asd"
}
}
// MARK UICollectionViewDataSource
extension CategoriesViewController:
UICollectionViewDataSource
{
func numberOfSections(in collectionView: UICollectionView) ->
Int {
return 1
}
func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
return categories.count
}
func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell =
collectionView.dequeueReusableCell(withReuseIdentifier: "CategoriesCollectionViewCell",for:indexPath) as!
CategoriesCollectionViewCell
let category = categories[indexPath.item]
cell.category = category
return cell
}
}
extension CategoriesViewController: UIScrollViewDelegate, UICollectionViewDelegate
{
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let layout = self.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
let cellWidthincludingSpacing = layout.itemSize.width+layout.minimumLineSpacing
var offset = targetContentOffset.pointee
let index = (offset.x + scrollView.contentInset.left) / cellWidthincludingSpacing
let roundedIndex = round(index)
offset = CGPoint(x: roundedIndex*cellWidthincludingSpacing-scrollView.contentInset.left, y: scrollView.contentInset.top)
targetContentOffset.pointee = offset
}
}
and second one is my products list controller, that must receive category name and put inside view
//
import UIKit
class ProductsViewController: UIViewController {
#IBOutlet weak var categoryTitle: UILabel!
var titleOfCategory:String = ""
#IBOutlet weak var collectionView: UICollectionView!
var products = Product.fetchProducts()
// let cellScale: CGFloat = 0.63
override func viewDidLoad() {
super.viewDidLoad()
categoryTitle.text = titleOfCategory
// let screenSize = UIScreen.main.bounds.size
// let cellWidth = floor(screenSize.width * cellScale)
// let cellHeight = floor(screenSize.height * cellScale)
// let insetX = (view.bounds.width - cellWidth) / 2
// let insetY = (view.bounds.height - cellHeight) / 2
// let layout = collectionView!.collectionViewLayout as! UICollectionViewFlowLayout
// layout.itemSize = CGSize(width:cellWidth,height:cellHeight)
// collectionView.contentInset = UIEdgeInsets(top:insetY,left:insetX,bottom:insetY,right:insetX)
// collectionView.dataSource = self
// collectionView.delegate = self
}
}
// MARK UICollectionViewDataSource
extension ProductsViewController:
UICollectionViewDataSource
{
func numberOfSections(in collectionView: UICollectionView) ->
Int {
return 1
}
func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
return products.count
}
func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell =
collectionView.dequeueReusableCell(withReuseIdentifier: "ProductsCollectionViewCell",for:indexPath) as!
ProductsCollectionViewCell
let product = products[indexPath.item]
cell.product = product
return cell
}
}
extension ProductsViewController: UIScrollViewDelegate, UICollectionViewDelegate
{
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let layout = self.collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
let cellWidthincludingSpacing = layout.itemSize.width+layout.minimumLineSpacing
var offset = targetContentOffset.pointee
let index = (offset.x + scrollView.contentInset.left) / cellWidthincludingSpacing
let roundedIndex = round(index)
offset = CGPoint(x: roundedIndex*cellWidthincludingSpacing-scrollView.contentInset.left, y: scrollView.contentInset.top)
targetContentOffset.pointee = offset
}
}
1, add didSelectItemAt to your collectionView, this will handle the click on the cell.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: "showProducts", sender: categories[indexPath.item])
}
2, In your CategoriesViewController start type "prepare" and you will see the prepare for segue method.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showProducts" {
let destination = segue.destination as! ProductsViewController
destination.titleOfCategory = sender as? String
}
}
I am currently working on a project and basically, I am still learning.
I was using at the beginning a UITableView, but I needed automatic height and 2 or 3 columns (depending on the device).
For the columns, I am using UICollectionViewFlowLayout.
In general, I am using only Labels and StackViews; a few warnings like Unable to simultaneously satisfy constraints (but I changed in a few ones priorities and is working but the performance is still really bad.
I am not retrieving info from backend, nothing spectacular.
The CustomLayout as follows:
public protocol CollectionViewFlowLayoutDelegate: class {
func numberOfColumns() -> Int
func height(at indexPath: IndexPath) -> CGFloat
}
public class CustomLayout: UICollectionViewFlowLayout {
private let cellPadding: CGFloat = 4
public var cache: [IndexPath : UICollectionViewLayoutAttributes] = [:]
private var contentHeight: CGFloat = 0
private var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
public weak var flowDelegate: CollectionViewFlowLayoutDelegate?
public override var collectionViewContentSize: CGSize {
return CGSize(width: self.contentWidth, height: self.contentHeight)
}
public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributesArray = [UICollectionViewLayoutAttributes]()
if cache.isEmpty {
self.prepare()
}
for (_, layoutAttributes) in self.cache {
if rect.intersects(layoutAttributes.frame) {
layoutAttributesArray.append(layoutAttributes)
}
}
return layoutAttributesArray
}
public override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return self.cache[indexPath]
}
public override func prepare() {
super.prepare()
cache.removeAll()
guard let collectionView = self.collectionView else {
return
}
let numberOfColumns = self.flowDelegate?.numberOfColumns() ?? 1
self.contentHeight = 0
let columnWidth = UIScreen.main.bounds.width / CGFloat(numberOfColumns) - CGFloat(numberOfColumns-1) * cellPadding
var xOffset = [CGFloat]()
for column in 0 ..< numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let photoHeight = self.flowDelegate?.height(at: indexPath) ?? 1
let height = cellPadding * 2 + photoHeight
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
self.cache[indexPath] = attributes
self.contentHeight = max(self.contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
}
public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
I do need the 2 or 3 columns with the automatic height. But what is really important as in any other project: Performance.
Thank you very much in advance.
Turns out that on my ViewControllers, on the func height(at indexPath: IndexPath) -> CGFloat protocol, I was calculating the height each time, instead of only retrieving it from an array.
I want to reorder my cells in my "Waterfall" collectionview. But when I move my cell, the size changes. To make my layout, I used this tutorial https://www.raywenderlich.com/164608/uicollectionview-custom-layout-tutorial-pinterest-2
How can I fix the size of my item when this position changes ?
My ViewLayout:
import Foundation
import UIKit
protocol WidgetCollectionViewLayoutDelegate: class {
func collectionView(_ collectionView: UICollectionView, heightForPhotoAt indexPath:IndexPath) -> CGFloat
}
class WidgetCollectionViewLayout: UICollectionViewLayout {
weak var delegate: WidgetCollectionViewLayoutDelegate!
private let numberOfColumns: Int = 2
private let cellPadding: CGFloat = 6
private var cache = [UICollectionViewLayoutAttributes]()
private var contentHeight: CGFloat = 0
private var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
print("prepare")
super.prepare()
guard cache.isEmpty == true, let collectionView = collectionView else {
return
}
calculContent()
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cache[indexPath.item]
}
private func calculContent() {
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset = [CGFloat]()
for column in 0 ..< numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
for item in 0 ..< collectionView!.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let photoHeight = delegate.collectionView(collectionView!, heightForPhotoAt: indexPath)
let height = cellPadding * 2 + photoHeight
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
}
}
Thank you in advance for your help
I am working on a App where I can keep track of my substitutions of my youth soccer team.
Following a tutorial by Payal Gupta on drag & drop into collections & tables I managed to get a drag and drop between two collection views (PlayersOntoTheField and Substitutes) working Screenshot.
When I drag a substitute player into my playground it should now snap to the predefined team line-up (e.g. 3-2-1 in the screenshot). Is it possible to get such behavior with a custom UICollectionViewLayout or does anyone have another suggestion?
Thank you you very much in advance for any help.
Danny
//Based on a work by:
//Payal Gupta (https://github.com/pgpt10/DragAndDrop-CollectionView)
import UIKit
class ViewController: UIViewController
{
private var substitutes = ["player1", "player2", "player3", "player4"]
private var players = [String]()
#IBOutlet weak var substitutesCollectionView: UICollectionView!
#IBOutlet weak var playersCollectionView: UICollectionView!
override func viewDidLoad()
{
super.viewDidLoad()
//SubstitutesCollectionView drag and drop configuration
self.substitutesCollectionView.dragInteractionEnabled = true
self.substitutesCollectionView.dragDelegate = self
self.substitutesCollectionView.dropDelegate = self
//PlayersCollectionView drag and drop configuration
self.playersCollectionView.dragInteractionEnabled = true
self.playersCollectionView.dropDelegate = self
self.playersCollectionView.dragDelegate = self
self.playersCollectionView.reorderingCadence = .fast //default value - .immediate
}
//MARK: Private Methods
private func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
{
let items = coordinator.items
if items.count == 1, let item = items.first, let sourceIndexPath = item.sourceIndexPath
{
var dIndexPath = destinationIndexPath
if dIndexPath.row >= collectionView.numberOfItems(inSection: 0)
{
dIndexPath.row = collectionView.numberOfItems(inSection: 0) - 1
}
collectionView.performBatchUpdates({
if collectionView === self.playersCollectionView
{
self.players.remove(at: sourceIndexPath.row)
self.players.insert(item.dragItem.localObject as! String, at: dIndexPath.row)
}
else
{
self.substitutes.remove(at: sourceIndexPath.row)
self.substitutes.insert(item.dragItem.localObject as! String, at: dIndexPath.row)
}
collectionView.deleteItems(at: [sourceIndexPath])
collectionView.insertItems(at: [dIndexPath])
})
coordinator.drop(items.first!.dragItem, toItemAt: dIndexPath)
}
}
private func copyItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
{
collectionView.performBatchUpdates({
var indexPaths = [IndexPath]()
for (index, item) in coordinator.items.enumerated()
{
let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
if collectionView === self.playersCollectionView
{
self.players.insert(item.dragItem.localObject as! String, at: indexPath.row)
}
else
{
self.substitutes.insert(item.dragItem.localObject as! String, at: indexPath.row)
}
indexPaths.append(indexPath)
}
collectionView.insertItems(at: indexPaths)
})
}
}
// MARK: - UICollectionViewDataSource Methods
extension ViewController : UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return collectionView == self.substitutesCollectionView ? self.substitutes.count : self.players.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
if collectionView == self.substitutesCollectionView
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! MyCollectionViewCell
cell.customImageView?.image = UIImage(named: self.substitutes[indexPath.row])
cell.customLabel.text = self.substitutes[indexPath.row].capitalized
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! MyCollectionViewCell
cell.customImageView?.image = UIImage(named: self.players[indexPath.row])
cell.customLabel.text = self.players[indexPath.row].capitalized
return cell
}
}
}
// MARK: - UICollectionViewDragDelegate Methods
extension ViewController : UICollectionViewDragDelegate
{
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem]
{
let item = collectionView == substitutesCollectionView ? self.substitutes[indexPath.row] : self.players[indexPath.row]
let itemProvider = NSItemProvider(object: item as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem]
{
let item = collectionView == substitutesCollectionView ? self.substitutes[indexPath.row] : self.players[indexPath.row]
let itemProvider = NSItemProvider(object: item as NSString)
let dragItem = UIDragItem(itemProvider: itemProvider)
dragItem.localObject = item
return [dragItem]
}
func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters?
{
if collectionView == substitutesCollectionView
{
let previewParameters = UIDragPreviewParameters()
previewParameters.visiblePath = UIBezierPath(rect: CGRect(x: 15, y: 5, width: 30, height: 30))
return previewParameters
}
return nil
}
}
// MARK: - UICollectionViewDropDelegate Methods
extension ViewController : UICollectionViewDropDelegate
{
func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool
{
return session.canLoadObjects(ofClass: NSString.self)
}
func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal
{
if collectionView === self.substitutesCollectionView
{
if collectionView.hasActiveDrag
{
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
else
{
return UICollectionViewDropProposal(operation: .forbidden)
}
}
else
{
if collectionView.hasActiveDrag
{
return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
else
{
return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
}
}
}
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator)
{
let destinationIndexPath: IndexPath
if let indexPath = coordinator.destinationIndexPath
{
destinationIndexPath = indexPath
}
else
{
// Get last index path of table view.
let section = collectionView.numberOfSections - 1
let row = collectionView.numberOfItems(inSection: section)
destinationIndexPath = IndexPath(row: row, section: section)
}
switch coordinator.proposal.operation
{
case .move:
self.reorderItems(coordinator: coordinator, destinationIndexPath:destinationIndexPath, collectionView: collectionView)
break
case .copy:
self.copyItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)
default:
return
}
}
}
That my workaround for custom UICollectionViewLayout so far:
import UIKit
class LineUp_3_2_1View: UICollectionViewLayout {
private var center: CGPoint!
private var itemSize: CGSize!
private var radiusOfCircleViews: CGFloat!
private var numberOfItems: Int!
override func prepare() {
super.prepare()
guard let collectionView = collectionView else { return }
radiusOfCircleViews = CGFloat(30.0)
itemSize = CGSize(width: radiusOfCircleViews * 2, height: radiusOfCircleViews * 2)
center = CGPoint(x: collectionView.bounds.midX, y: collectionView.bounds.midY)
numberOfItems = collectionView.numberOfItems(inSection: 0)
}
override var collectionViewContentSize: CGSize {
return collectionView!.bounds.size
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
if (indexPath.item == 0) {attributes.center = CGPoint(x: 169, y: 344)}
if (indexPath.item == 1) {attributes.center = CGPoint(x: 46, y: 250)}
if (indexPath.item == 2) {attributes.center = CGPoint(x: 169, y: 250)}
if (indexPath.item == 3) {attributes.center = CGPoint(x: 287, y: 250)}
if (indexPath.item == 4) {attributes.center = CGPoint(x: 80, y: 156)}
if (indexPath.item == 5) {attributes.center = CGPoint(x: 253, y: 156)}
if (indexPath.item == 6) {attributes.center = CGPoint(x: 169, y: 62)}
attributes.size = itemSize
return attributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return (0 ..< collectionView!.numberOfItems(inSection: 0))
.flatMap { item -> UICollectionViewLayoutAttributes? in // `compactMap` in Xcode 9.3
self.layoutAttributesForItem(at: IndexPath(item: item, section: 0))
}
}
}
I have recently setup FireBase, but have not yet figured out how to embed the children of the "Posts" section into each individual UICollectionViewCell. Currently, the ViewController has this bit of code, where ipCell is the indexPath of the cell. What is returned is no description at all. I hope you can understand, since this has really been bothering me. The array posts is defined before.
import UIKit
import FirebaseDatabase
import FireBase
var posts = [String]()
var ipCell = Int()
var count = Int()
var description = String()
class HomeController: UICollectionViewController,
UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
var newCellN = Int()
let ref = Database.database().reference().child("Posts")
override func viewDidLoad() {
super.viewDidLoad()
count = newCellN
collectionView?.register(PostCell.self, forCellWithReuseIdentifier:
cellId)
// Do any additional setup after loading the view, typically from a
nib.
}
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return newCellN
}
func collectionView(collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex
section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 15.0, left: 0.0, bottom: 0.0, right: 0.0)
}
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
cellId, for: indexPath)
cell.contentView.layer.borderWidth = 0.5
cell.contentView.layer.cornerRadius = 10
cell.contentView.layer.borderColor = UIColor.lightGray.cgColor
cell.backgroundColor = .white /* #040504 */
ipCell = indexPath.item
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,sizeForItemAt indexPath:
IndexPath) -> CGSize {
return CGSize(width: view.frame.width-20, height: 250)
}
class PostCell : UICollectionViewCell {
override init (frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setUp() {
addSubview(profilePic)
addSubview(TextF)
addSubview(username)
addSubview(descript)
let screenW = UIScreen.main.bounds.size.width
TextF.frame = CGRect(x: 85, y: 5, width: screenW-110, height:
48)
profilePic.frame = CGRect(x: 5, y: 5, width: 80, height: 80)
username.frame = CGRect(x:85, y:40, width: screenW-110, height:
22)
descript.frame = CGRect(x: 5, y: 95, width: screenW-40,
height:105)
}
override func awakeFromNib() {
super.awakeFromNib()
}
let profilePic: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "shadowcypher-1")
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let TextF: UITextView = {
let textV = UITextView()
textV.textColor = .black
textV.backgroundColor = .white
textV.toggleBoldface(nil.self)
textV.font = .systemFont(ofSize: 24)
textV.translatesAutoresizingMaskIntoConstraints = false
textV.isEditable = false
return textV
}()
let username: UITextView = {
let view = UITextView()
view.textColor = .blue
view.font = .systemFont(ofSize: 12)
view.text = "#sonic"
switch ipCell {
case 0:
view.text = "#timcook"
break
case 1:
view.text = "#philschiller"
break
case 2:
view.text = "#sundarpichai"
break
default:
view.text = "#timmy"
break
}
view.backgroundColor = .white
view.isEditable = false
view.translatesAutoresizingMaskIntoConstraints = false
view.isScrollEnabled = false
return view
}()
let descript: UITextView = {
let desV = UITextView()
desV.textColor = .black
Database.database().reference().child("Posts").observeSingleEvent(of:
.value, with: {(snap) in
if let snapDict = snap.value as? [String:AnyObject]{
var i = count + 1
for each in snapDict{
let keyID = each.key
let childValue = each.value["post"] as! String
posts.append("\(childValue)")
print("\(posts)")
}
}
})
desV.isEditable = false
let v = 0
while (v < posts.count) {
if (ipCell == v) {
desV.text = posts[v]
}
}
desV.font = .systemFont(ofSize: 16)
return desV
}()
}
}