how to add swipe gesture or swipe function between two overlap container view using segmented control, like instagram profile? - swift

I am new to iOS and trying to build an app to learn more. I'm stuck at the last stage of my application. I want to be able to swipe between two container views using segmented control. I want to add two overlapping container views (container views with an embed segue with child controller) of the same size on half screen in single controller like instagram profile. I want to add a tableview to both child controllers. When I run the app the data of the first child view should be seen but when I swipe left, the second child controller should be seen with same size and in the same position. I want this to be like an instagram profile.
Currently, when I swipe left the second child controller opens in full screen and hides everything else on that screen. I have tried various tutorials, but to no avail.
Can you help me to do this?
Thank You!
This is my view controller's code
// CODE //
{
//
// ViewController.swift
// BeautyParlor
//
// Created by Mohammad Affan Siddiqui on 20/11/2019.
// Copyright © 2019 Mohammad Affan Siddiqui. All rights reserved.
//
import UIKit
//import PinterestLayout
class ViewController: UIViewController {
#IBOutlet weak var SegmentedControl: UISegmentedControl!
#IBOutlet weak var thirdView: UIView!
#IBOutlet weak var collectionViewOutletPortfolio: UICollectionView!
#IBOutlet weak var collectionViewOutletAbout: UICollectionView!
#IBOutlet weak var secondView: UIView!
#IBOutlet weak var firstView: UIView!
#IBOutlet weak var collectionViewOutletStatic: UICollectionView!
// FOR STATIC DATA
var arrimgbackground = [UIImage]()
var arrimglogo = [UIImage]()
var arrimglocation = [UIImage]()
var arrimginsta = [UIImage]()
var arrlblname = ["ABC Saloon"]
var arrlblrating = ["Rating 4.5/5"]
var arrlbllocation = ["ABC,Street,karachi"]
var arrlblinsta = ["qqq"]
var arrlblservicename = ["We are serving you"]
var arrlblrs = ["Rs:200"]
// FOR ABOUT DATA
var arrlbldescription = ["Before you can begin to determine what the will grow. The whole process is an organic one—a natural progression from a seed to a full-blown "]
// FOR PORTFOLIO DATA
var arrimgportfolio = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
//
//
//
//
// setupSegmentedContrl()
setupHorizontalBar()
// let swipright = UISwipeGestureRecognizer(target: self, action: #selector(self.swipGesture))
// swipright.direction = UISwipeGestureRecognizer.Direction.right
// self.thirdView?.addGestureRecognizer(swipright)
// let rightSwipe = UISwipeGestureRecognizer(target: SegmentCotroller, action: Selector("swiped:"))
// rightSwipe.direction = .Right
// self.SegmentCotroller.addGestureRecognizer(rightSwipe)
//
let rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector(("swiped:")))
rightSwipe.direction = .right
self.secondView?.addGestureRecognizer(rightSwipe)
// let swipright = UISwipeGestureRecognizer(target: self, action: #selector(self.swipGesture))
// swipright.direction = UISwipeGestureRecognizer.Direction.right
// self.secondView?.addGestureRecognizer(swipright)
//
//
// let layout = PinterestLayout()
// collectionViewOutletPortfolio.collectionViewLayout = layout
//
// layout.delegate = self
// layout.cellPadding = 5
// layout.numberOfColumns = 2
//
//
//
// if let layout = collectionViewOutletPortfolio?.collectionViewLayout as? PinterestLayout {
// layout.delegate = self as! PinterestLayoutDelegate
// }
//
thirdView?.isHidden = true
arrimgbackground = [#imageLiteral(resourceName: "d.png")]
arrimglogo = [#imageLiteral(resourceName: "roundimage.png")]
arrimglocation = [#imageLiteral(resourceName: "location.jpeg")]
arrimginsta = [#imageLiteral(resourceName: "insta.png")]
arrimgportfolio = [#imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "c.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "d.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "down.png"), #imageLiteral(resourceName: "down.png")]
// setupSegmentedControl().topAnchor.constraintEqualToAnchor(topLayoutGuide)
}
private func setupHorizontalBar(){
}
private func setupSegmentedControl(){
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// SegmentedControl
}
// #objc func swipGesture(sender: UISwipeGestureRecognizer?){
// // #objc func swipeAction (swipe: UISwipeGestureRecognizer) {
// if let swipGesture = sender{
// switch swipGesture.direction {
// case UISwipeGestureRecognizer.Direction.right:
// print ("i just swip right")
// let redVC = UIViewController()
// redVC.view.backgroundColor = UIColor.red
// //self.navigationController?.popViewController(animated: true)
// //performSegue(withIdentifier: "goRight", sender: self)
// default:
// break
// }
// }
//
// }
// thirdView = uivi(frame: thirdView)
//self.collectionViewOutletPortfolio? = UICollectionView()
// ViewController.swipGesture(index: index)(index: index)
// case UISwipeGestureRecognizer.Direction.left:
// print ("i just swiped left")
////
// // arrlbl = UICollectionView()
// default:
// break
//
// }
// }
// FOR SWIPPING CHECK WORKING OR NOT
// #IBAction func swipBetweenViews(_ sender: UISwipeGestureRecognizer) {
// print ("HelowSwipped")
//
//}
#IBAction func switchViews(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
firstView.isHidden = false
secondView?.isHidden = false
thirdView?.isHidden = true
// firstView.alpha = 0
// secondView.alpha = 1
// thirdView.alpha = 0
//
}else{
firstView.isHidden = false
secondView?.isHidden = true
thirdView?.isHidden = false
// firstView.alpha = 0
// secondView.alpha = 0
// thirdView.alpha = 1
}
}
}
extension ViewController: UICollectionViewDataSource , UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == collectionViewOutletStatic){
let cell = collectionViewOutletStatic.dequeueReusableCell(withReuseIdentifier: "cellone", for: indexPath)as! CollectionViewCellStatic
cell.imgbackground.image = arrimgbackground[indexPath.row]
cell.imglogo.image = arrimglogo[indexPath.row]
cell.imglocation.image = arrimglocation[indexPath.row]
cell.imginsta.image = arrimginsta[indexPath.row]
cell.lblname.text = arrlblname[indexPath.row]
cell.lblrating.text = arrlblrating[indexPath.row]
cell.lbllocation.text = arrlbllocation[indexPath.row]
cell.lblinstaname.text = arrlblinsta[indexPath.row]
cell.lblservicename.text = arrlblservicename[indexPath.row]
cell.lblrs.text = arrlblrs[indexPath.row]
return cell
}else{
if (collectionView == collectionViewOutletAbout){
let cello = collectionViewOutletAbout.dequeueReusableCell(withReuseIdentifier: "celltwo", for: indexPath)as! CollectionViewCellAbout
cello.lbldescription.text = arrlbldescription[indexPath.row]
return cello
}else{
let cellt = collectionViewOutletPortfolio?.dequeueReusableCell(withReuseIdentifier: "cellthree", for: indexPath)as! CollectionViewCellPortfolio
cellt.imgPortfolio.image = arrimgportfolio[indexPath.row]
return cellt
// THIS CODE FOR 3 COLUMNS OF IMAGES COLLECTION LIKE PORFOLIO
// _ = UIScreen.main.bounds.width/2-2
// let layout = UICollectionViewFlowLayout()
//
// collectionViewOutletPortfolio?.collectionViewLayout = layout
//
// layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
// // layout.itemSize = CGSize(width: itemSize, height: itemSize)
////
//// layout.minimumInteritemSpacing = 0
//// layout.minimumLineSpacing = 0
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// let x = CGFloat(indexPath.item) * frame.width
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == collectionViewOutletStatic){
return arrimgbackground.count
}else{
if (collectionView == collectionViewOutletAbout){
return arrlbldescription.count
}else{
return arrimgportfolio.count
}
}
}
}
extension ViewController: UICollectionViewDelegateFlowLayout{
// THIS FOR 3 COLUMNS OF IMAGES IN CLLECTION VIEW CELL
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let collectionwidth = collectionView.bounds.width
return CGSize(width: collectionwidth/3, height: collectionwidth/3)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
//extension ViewController: PinterestLayoutDelegate{
// func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGSize {
// //return UIImage(named: row[indexPath.item].imageename)?.size
//
// }
//}
//
//extension ViewController: PinterestLayoutDelegate{
// func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat {
// return 100
// }
//
//
//
// func collectionView(
// _ collectionView: UICollectionView,
// heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat {
// return arrimgportfolio[indexPath.row]
// //return arrimgportfolio[indexPath.item].image.size.height
// }

This is the simple example that you want. This is design for full screen. I think you can get an idea and customize this for your requirement
class ContainerController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.0, *) {
view.backgroundColor = .systemBackground
} else {
view.backgroundColor = .white
}
navigationItem.titleView = sgControll
updateView()
sgControll.addTarget(self, action: #selector(segmentControllValueChanged (_:)), for:.valueChanged)
}
//MARK: Components
let sgControll:UISegmentedControl = {
let sg = UISegmentedControl()
sg.insertSegment(withTitle: "first Child", at: 0, animated: true)
sg.insertSegment(withTitle: "Second Child", at: 1, animated: true)
sg.selectedSegmentIndex = 0
return sg
}()
private lazy var secondView : SecondChildViewController = {
let vc = SecondChildViewController()
self.add(asChildViewController: vc)
return vc
}()
private lazy var firstView:FirstChildViewController = {
let vc = FirstChildViewwController()
self.add(asChildViewController: vc)
return vc
}()
}
//MARK: Functions
extension ContainerController {
#objc func segmentControllValueChanged(_ sender : UISegmentedControl){
print(sender.selectedSegmentIndex)
updateView()
}
private func add(asChildViewController viewController: UIViewController){
addChild(viewController)
view.addSubview(viewController.view)
viewController.view.translatesAutoresizingMaskIntoConstraints = false
viewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
viewController.didMove(toParent: self)
}
private func remove(asChildViewController viewController: UIViewController) {
viewController.willMove(toParent: nil)
viewController.view.removeFromSuperview()
viewController.removeFromParent()
}
private func updateView() {
if sgControll.selectedSegmentIndex == 0 {
remove(asChildViewController: firstView)
add(asChildViewController: secondView)
} else {
remove(asChildViewController: seconView)
add(asChildViewController: firstView)
}
}
}

Related

Trying to create new NSTextView every time the attributed string exceeds a certain height?

I'm trying to add a new NSTextView to the last index in my collection view every time the attributed string exceeds a certain bounds. The code works perfectly until the 5th item then it starts its starts creating an item every time the enter button is pressed. I'm thinking its a bug but im not sure. if any one can show me a better way to do it or improve the current code I have I would appreciate it. Below is my code:
Here is the CollectionViewItem
class DocumentItem: NSCollectionViewItem {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
self.itemView?.wantsLayer = true
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
}
func getView() -> DocumentTextView {
return self.itemView!
}
}
Here is the collectionView datasource
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return DocList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DocumentItem"), for: indexPath)
return item
}
Here is the NSTextView subclass
class DocumentTextView: NSTextView {
var theContainer = NSTextContainer()
var theStorage = NSTextStorage()
var theManager = NSLayoutManager()
var table = NSTextTable()
var pdfPage: PDFPage?
override init(frame frameRect: NSRect) {
super.init(frame: NSRect(origin: frameRect.origin, size: NSSize(width: 800, height: 1131 )), textContainer: theContainer)
theStorage.addLayoutManager(theManager)
theManager.addTextContainer(theContainer)
self.textContainerInset = CGSize(width: 50, height: 50)
self.textContainer?.widthTracksTextView = true
self.textContainer?.heightTracksTextView = true
self.textContainer?.lineBreakMode = .byWordWrapping
self.maxSize = NSSize(width: 800, height: 1131)
self.backgroundColor = NSColor.fromHexString("ffffff")!
self.isRichText = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is the function bringing the bug
func textDidChange(_ notification: Notification) {
var textView = notification.object as? DocumentTextView
let numberOfItems = theDocumentOutlineView.numberOfItems(inSection: 0)
let theLastTextView = theDocumentOutlineView.item(at: numberOfItems - 1) as! DocumentItem
if textView == theLastTextView.itemView {
print(textView?.attributedString().size())
if (textView?.attributedString().size().height)! >= 1106.0 {
self.DocList.append(2)
var set = Set<IndexPath>()
set.insert(NSIndexPath(forItem: self.DocList.count - 1 , inSection: 0) as IndexPath)
theDocumentOutlineView.insertItems(at: set)
theDocumentOutlineView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
var newFirstResponder = theDocumentOutlineView.item(at: self.DocList.count - 1) as! DocumentItem
newFirstResponder.itemView?.delegate = self
self.view.window?.makeFirstResponder(newFirstResponder.itemView)
}
}
}
Here's my test project, maybe it helps. The delegate of the text view is its view controller, the NSCollectionViewItem. The view controller of the collection view also receives NSText.didChangeNotification notifications to check the length of the text. heightTracksTextView of the text container is false.
ViewController:
class ViewController: NSViewController, NSCollectionViewDataSource, NSCollectionViewDelegate {
#IBOutlet weak var collectionView: NSCollectionView!
var docList: [DocumentObject] = [DocumentObject(index: 0, string: NSAttributedString(string: "New 0"))]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(DocumentItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"))
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange),
name: NSText.didChangeNotification, object: nil)
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return docList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
if let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"),
for: indexPath) as? DocumentItem {
item.representedObject = docList[indexPath.item]
return item
}
return NSCollectionViewItem()
}
#objc func textDidChange(_ notification: Notification) {
if let textView = notification.object as? NSTextView {
if let theLastItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem,
textView === theLastItem.itemView {
//if textView.attributedString().size().height >= 1106.0 {
print("\(textView.attributedString().size().height) \(textView.layoutManager!.usedRect(for: textView.textContainer!).size.height)")
if let textContainer = textView.textContainer,
let heigth = textView.layoutManager?.usedRect(for: textContainer).size.height,
heigth >= 1106.0 {
DispatchQueue.main.async {
if let window = self.view.window,
window.makeFirstResponder(nil) { // end editing of previous item
self.docList.append(DocumentObject(index: self.docList.count - 1, string: NSAttributedString(string: "New \(self.docList.count)")))
let set: Set = [IndexPath(item: self.docList.count - 1, section: 0)]
self.collectionView.insertItems(at: set)
self.collectionView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
if let newItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem {
window.makeFirstResponder(newItem.itemView)
}
}
}
}
}
}
}
}
DocumentItem:
class DocumentItem: NSCollectionViewItem, NSTextViewDelegate {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
self.itemView?.delegate = self
}
override var representedObject: Any? {
didSet {
if let item = representedObject as? DocumentObject {
itemView?.textStorage?.setAttributedString(item.string)
}
}
}
func textDidEndEditing(_ notification: Notification) {
if let item = representedObject as? DocumentObject {
item.string = itemView?.textStorage?.copy() as! NSAttributedString
}
}
}
DocumentObject:
class DocumentObject {
var index: Int
var string: NSAttributedString
init(index: Int, string: NSAttributedString) {
self.index = index
self.string = string
}
}

How to create a new collectionView when switching to another calendarView

I am having trouble trying to create a new collection view. I want to effectively have a collectionView with unique properties and then when I click on a date in my view controller it changes to a effectively a blank collectionView template so that the user can then put it there recipes.
How would I go about changing the collectionView (when user clicked on a date), change to a collection-view template and then save when the user puts in data?
Here is the code for the controller along with a picture example:
import UIKit
import GCCalendar
class CalendarViewController123: UIViewController, UICollectionViewDelegate {
// MARK: Properties
fileprivate var calendarView: GCCalendarView!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var datelabel: UILabel!
#IBOutlet weak var open: UIBarButtonItem!
#IBAction func trytoday(_ sender: Any) {
self.calendarView.select(date: Date())
}
}
// MARK: - View
extension CalendarViewController123 {
override func viewDidLoad() {
super.viewDidLoad()
open.target = revealViewController()
open.action = #selector(SWRevealViewController.revealToggle(_:))
self.addToolbar()
self.addCalendarView()
self.addConstraints()
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for:.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
}
}
// MARK: - Toolbar
extension CalendarViewController123 {
fileprivate func addToolbar() {
self.navigationController!.isToolbarHidden = false
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let displayMode = UIBarButtonItem(title: "Display Mode", style: .plain, target: self, action: #selector(self.displayMode))
self.toolbarItems = [ space, displayMode]
}
#objc func displayMode() {
self.calendarView.displayMode = (self.calendarView.displayMode == .month) ? .week : .month
}
}
// MARK: - Calendar View
fileprivate extension CalendarViewController123 {
func addCalendarView() {
self.calendarView = GCCalendarView()
self.calendarView.delegate = self
self.calendarView.displayMode = .week
self.calendarView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.calendarView)
}
}
// MARK: - Constraints
fileprivate extension CalendarViewController123 {
func addConstraints() {
self.calendarView.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 2).isActive = true
self.calendarView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.calendarView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
self.calendarView.heightAnchor.constraint(equalToConstant: 325).isActive = true
}
}
// MARK: - GCCalendarViewDelegate
extension CalendarViewController123: GCCalendarViewDelegate {
func calendarView(_ calendarView: GCCalendarView, didSelectDate date: Date, inCalendar calendar: Calendar) {
let dateFormatter = DateFormatter()
dateFormatter.calendar = calendar
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "MMM dd", options: 0, locale: calendar.locale)
//yyyy
// self.navigationItem.title = dateFormatter.string(from: date)
self.datelabel.text = dateFormatter.string(from: date)
}
}
The Green is the collectionView on a view controller
It depends on what data you are showing and how you are retrieving it. If you can provide more information I will update my answer accordingly.
1. Select Date
#IBAction func trytoday(_ sender: Any) {
self.calendarView.select(date: Date())
self.fetchData(forDate: selectedDate)
}
2. Fetch Data
func fetchData(forDate date: Date) {
//Fetch data and return array of objects
self.objects = retreivedObjects
self.collectionView.reloadData()
}
3. Load Data
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return objects.count
}
4. Setup Cell with Data
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? Cell else { return UICollectionViewCell}
cell.configure(withObject: objects[indexPath.item])
return cell
}

Pass image from collection to viewcontroller swift

i haave problem i can't Pass ImageView From collection to viewcontroller using Firebase Database
This My Code
import UIKit
import Firebase
import FirebaseDatabase
import SDWebImage
import FirebaseStorage
import KRProgressHUD
class ViewControllerCollocation: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var MyColloctaion: UICollectionView!
var imagePicker = UIImagePickerController()
var images = [ImagePost]()
var dbRef:DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
setutxent()
designCollectionView()
imagePicker.delegate = self
dbRef = Database.database().reference().child("Images")
/////////
loadDB()
KRProgressHUD.set(style: .custom(background: .black, text: .white, icon: nil))
KRProgressHUD.show(withMessage: "Loading...")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
KRProgressHUD.dismiss()
}
}
func loadDB(){
dbRef.observe(DataEventType.value, with: { (snapshot) in
var newImages = [ImagePost]()
for imageFireSnapshot in snapshot.children {
let ImagesFireObject = ImagePost(snapshot: imageFireSnapshot as! DataSnapshot)
newImages.append(ImagesFireObject)
}
self.images = newImages
self.MyColloctaion.reloadData()
}
)}
func collectionView(_ colloction: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
internal func collectionView(_ colloction: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = colloction.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! UploadOneCollectionViewCell
let image = images[indexPath.row]
cell.ImageView.layer.cornerRadius = 13
cell.ImageView.clipsToBounds = true
cell.ImageView.sd_setImage(with: URL(string: image.url), placeholderImage: UIImage(named: "Image1"))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func designCollectionView() {
let itemSize = UIScreen.main.bounds.width/3 - 3
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.itemSize = CGSize(width: itemSize, height: 230)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
//layout.scrollDirection = .horizontal
self.MyColloctaion.isPagingEnabled = true
MyColloctaion.collectionViewLayout = layout
}
func steupbar(){
navigationController?.navigationBar.barTintColor = UIColor.black
tabBarController?.tabBar.barTintColor = UIColor.black
self.navigationController?.navigationBar.titleTextAttributes =
[NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: UIFont(name: "Baskerville-BoldItalic", size: 21)!]
}
#IBAction func Upload(_ sender: Any) {
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
func generateRandom(size: UInt) -> String {
let prefixSize = Int(min(size, 43))
let uuidString = UUID().uuidString.replacingOccurrences(of: "-", with: "")
return String(Data(uuidString.utf8)
.base64EncodedString()
.replacingOccurrences(of: "=", with: "")
.prefix(prefixSize))
}
}
this is My ""ImagePost.swift"""
import Foundation
import FirebaseDatabase
struct ImagePost {
let key: String!
let url:String!
let itemRef:DatabaseReference?
init(url:String, key:String) {
self.key = key
self.url = url
self.itemRef = nil
}
init(snapshot:DataSnapshot) {
key = snapshot.key
itemRef = snapshot.ref
let snapshotValue = snapshot.value as? NSDictionary
if let imageUrl = snapshotValue?["url"] as? String {
url = imageUrl
}else{
url = ""
}
}
}
and This is My detail view
import UIKit
class VC1: UIViewController {
var imageURL : String?
#IBOutlet weak var ImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
and Thanks for your help guys!
You can pass image to detail view by getting image in didselect method:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let image = images[indexPath.row]
let vc = self.storyboard?.instantiateViewController(withIdentifier: "VC1") as! VC1
vc.imageObject = images[indexPath.row]
self.navigationController?.pushViewController(vc, animated: false)
}
Just create a variable as imageObject in VC1 and pass data to it as shown above.

swift 3 table view with slide out menu

I got problem with making table view on the same view with slide menu, could you help me how to do that, I created view controller and embeded navigation controller, now I just want add table vie behind the slide menu and show table view with two section and show data with one custom cell.
#Egle Matutyte, I am supposing that you have done all work except SlideBar.
I am providing code for SlideBar. Just add and try.
First Add the SideBar class i.e. below without any change
import UIKit
#objc protocol SideBarDelegate{
func sideBarDidSelectButtonAtIndex(_ index:Int)
#objc optional func sideBarWillClose()
#objc optional func sideBarWillOpen()
}
class SideBar: NSObject, SideBarTableViewControllerDelegate {
let barWidth:CGFloat = 150.0
let sideBarTableViewTopInset:CGFloat = 64.0
let sideBarContainerView:UIView = UIView()
let sideBarTableViewController:SideBarTableViewController = SideBarTableViewController()
var originView:UIView = UIView()
var animator:UIDynamicAnimator!
var delegate:SideBarDelegate?
var isSideBarOpen:Bool = false
override init() {
super.init()
}
init(sourceView:UIView, menuItems:Array<String>){
super.init()
originView = sourceView
sideBarTableViewController.tableData = menuItems
setupSideBar()
animator = UIDynamicAnimator(referenceView: originView)
let showGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SideBar.handleSwipe(_:)))
showGestureRecognizer.direction = UISwipeGestureRecognizerDirection.right
originView.addGestureRecognizer(showGestureRecognizer)
let hideGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(SideBar.handleSwipe(_:)))
hideGestureRecognizer.direction = UISwipeGestureRecognizerDirection.left
originView.addGestureRecognizer(hideGestureRecognizer)
}
func setupSideBar(){
//sideBarContainerView.frame = CGRect(x: -barWidth - 1, y: originView.frame.origin.y, width: barWidth, height: originView.frame.size.height)
sideBarContainerView.frame = CGRect(x: -barWidth - 1, y: sideBarTableViewTopInset, width: barWidth, height: originView.frame.size.height)
sideBarContainerView.backgroundColor = UIColor.clear
sideBarContainerView.clipsToBounds = false
originView.addSubview(sideBarContainerView)
let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.light))
blurView.frame = sideBarContainerView.bounds
sideBarContainerView.addSubview(blurView)
sideBarTableViewController.delegate = self
sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
sideBarTableViewController.tableView.clipsToBounds = false
sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
sideBarTableViewController.tableView.backgroundColor = UIColor.clear
sideBarTableViewController.tableView.scrollsToTop = false
//sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(sideBarTableViewTopInset, 0, 0, 0)
sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(1, 0, 0, 0)
sideBarTableViewController.tableView.reloadData()
sideBarContainerView.addSubview(sideBarTableViewController.tableView)
}
func handleSwipe(_ recognizer:UISwipeGestureRecognizer){
if recognizer.direction == UISwipeGestureRecognizerDirection.left{
showSideBar(false)
delegate?.sideBarWillClose?()
}else{
showSideBar(true)
delegate?.sideBarWillOpen?()
}
}
func showSideBar(_ shouldOpen:Bool){
animator.removeAllBehaviors()
isSideBarOpen = shouldOpen
let gravityX:CGFloat = (shouldOpen) ? 0.5 : -0.5
let magnitude:CGFloat = (shouldOpen) ? 20 : -20
let boundaryX:CGFloat = (shouldOpen) ? barWidth : -barWidth - 1
let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
gravityBehavior.gravityDirection = CGVector(dx: gravityX, dy: 0)
animator.addBehavior(gravityBehavior)
let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
collisionBehavior.addBoundary(withIdentifier: "sideBarBoundary" as NSCopying, from: CGPoint(x: boundaryX, y: 20), to: CGPoint(x: boundaryX, y: originView.frame.size.height))
animator.addBehavior(collisionBehavior)
let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.instantaneous)
pushBehavior.magnitude = magnitude
animator.addBehavior(pushBehavior)
let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
sideBarBehavior.elasticity = 0.3
animator.addBehavior(sideBarBehavior)
}
func sideBarControlDidSelectRow(_ indexPath: IndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
showSideBar(false)
}
}
After this, add a new swift class
SideBarTableViewController
which inherit UITableViewController
import UIKit
protocol SideBarTableViewControllerDelegate{
func sideBarControlDidSelectRow(_ indexPath:IndexPath)
}
class SideBarTableViewController: UITableViewController {
var delegate:SideBarTableViewControllerDelegate?
var tableData:Array<String> = []
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell!.backgroundColor = UIColor.clear
cell!.textLabel?.textColor = UIColor.darkText
let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
cell!.selectedBackgroundView = selectedView
}
cell!.textLabel?.text = tableData[indexPath.row]
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 45
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.sideBarControlDidSelectRow(indexPath)
}
}
Now paste the code below in your TableViewController or the page on which you want to add SlideBar.
let the name of your page is Dashboard, add the delegate as below
class Dashboard: UIViewController, SideBarDelegate
{
//declare sidebar
var sideBar:SideBar = SideBar()
override func viewWillAppear(_ animated: Bool)
{
//Initialise the content of SlideBar Row
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Dashboard"])
sideBar.delegate = self
}
func sideBarControlDidSelectRow(_ indexPath: IndexPath) {
print("Selected from SlideBar")
}
func sideBarDidSelectButtonAtIndex(_ index: Int)
{
//
}
//Add a button(Optional)in ViewDidLoad()
override func viewDidLoad()
{
super.viewDidLoad()
let btn_Hamburger = UIButton(frame: CGRect(x: 10, y: 70, width: 100, height: 25))
btn_Hamburger.addTarget(self, action: #selector(btn_hamburger(sender:)), for: .touchUpInside)
//add Image on Hamburger button
btn_Hamburger.setImage(#imageLiteral(resourceName: "img_hemberger"), for: .normal)
view.addSubview(btn_Hamburger)
}
//To in and out SideBar menu
var flag:Bool = true
func btn_hamburger(sender: UIButton!)
{
if flag == true {
sideBar.showSideBar(true)
flag = false
}
else{
sideBar.showSideBar(false)
flag = true
}
}
}

UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0x79fe0f20> {length = 2, path = 0 - 4}

When I load the first time my UICollectionView does not have any problem, Im using custom layouts and a serachbar, when I search some text it crashes throwing the exception that the cell with an index path that does not exist, Im using the search bar like the next code:
import UIKit
import AVFoundation
class CategoryViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UISearchBarDelegate {
var ListArray : JSON! = []
var SelectedIds: [Int] = []
var SearchActive : Bool = false
var SearchArray = [Int]()
#IBOutlet weak var SearchCategories: UISearchBar!
#IBOutlet weak var CategoryCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
if let layout = self.CategoryCollection.collectionViewLayout as? InterestsLayout {
layout.delegate = self
}
self.CategoryCollection.backgroundColor = UIColor.clearColor()
self.CategoryCollection.contentInset = UIEdgeInsets(top: 18, left: 3, bottom: 10, right: 3)
// Search Delegate
self.SearchCategories.delegate = self
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.LoadData()
}
func LoadData() {
MUBService.categoriesList(self) { (categories_list) -> () in
self.ListArray = categories_list
self.CategoryCollection.reloadData()
self.view.hideLoading()
}
}
func dismissKeyboard() {
view.endEditing(true)
self.SearchCategories.showsCancelButton = false
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
self.SearchCategories.showsCancelButton = true
self.SearchActive = true
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
self.SearchActive = false
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.SearchActive = false
self.dismissKeyboard()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
self.SearchActive = false
}
func searchBar(searchBar: UISearchBar, let textDidChange searchText: String) {
self.SearchArray = []
for (index, object) in self.ListArray["categories"] {
let name = object["name"].string!
if name.localizedStandardContainsString(searchText) == true {
self.SearchArray.append(Int(index)!)
}
}
if(self.SearchArray.count == 0){
self.SearchActive = false;
} else {
self.SearchActive = true;
}
self.CategoryCollection.reloadData()
}
}
extension CategoryViewController {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
self.CategoryCollection?.collectionViewLayout.invalidateLayout()
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(self.SearchActive && self.SearchArray.count > 0) {
return self.SearchArray.count
}
return self.ListArray["categories"].count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CategoryCell", forIndexPath: indexPath) as! CategoryCell
let row = indexPath.row
if(self.SearchActive && self.SearchArray.count > 0) {
let category = self.ListArray["categories"][self.SearchArray[row]]
cell.configureWithPhoto(category, selected: self.ListArray["selected"])
}else{
let category = self.ListArray["categories"][row]
cell.configureWithPhoto(category, selected: self.ListArray["selected"])
}
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = self.CategoryCollection.cellForItemAtIndexPath(indexPath) as! CategoryCell
cell.changeBackGroundColor()
if (cell.is_active == true){
self.SelectedIds.append(cell.id)
}else{
self.SelectedIds.removeObject(cell.id)
}
}
#IBAction func RegisterDidTouch(sender: AnyObject) {
MUBService.setMyCategories(self.SelectedIds, view_controller: self) { (categories_selected) -> () in
self.performSegueWithIdentifier("HomeTabBarFromCategoriesSegue", sender: self)
}
}
}
extension CategoryViewController : InterestsLayoutDelegate {
// 1. Returns the photo height
func collectionView(collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:NSIndexPath , withWidth width:CGFloat) -> CGFloat {
var row = indexPath.row
if(self.SearchActive && self.SearchArray.count > 0) {
row = self.SearchArray[row]
}
let category = self.ListArray["categories"][row]
let url = NSURL(string:category["image"].string!)
let data = NSData(contentsOfURL:url!)
let image = UIImage(data:data!)!
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let rect = AVMakeRectWithAspectRatioInsideRect((image.size), boundingRect)
return rect.size.height
}
// 2. Returns the annotation size based on the text
func collectionView(collectionView: UICollectionView, heightForAnnotationAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat {
let annotationPadding = CGFloat(4)
let annotationHeaderHeight = CGFloat(17)
var row = indexPath.row
if(self.SearchActive && self.SearchArray.count > 0) {
row = self.SearchArray[row]
}
let category = self.ListArray["categories"][row]
let font = UIFont(name: "AvenirNext-Regular", size: 10)!
let rect = NSString(string: category["name"].string!).boundingRectWithSize(CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
let commentHeight = ceil(rect.height)
var height = annotationPadding + annotationHeaderHeight + commentHeight + annotationPadding
if (height != 70){
height = 70
}
return 70
}
}
I don't understand what is happening, thanks a lot for your help
I've faced the same problem. Here an explanation: if you use a custom collectionViewLayout and you have a cache for layout attributes (best practice so you don't have to calculate every time attributes), you have to override invalidateLayout method in your custom layout class and purge your cache.
Here's my layout attributes array
private var cache = [UICollectionViewLayoutAttributes]()
Here the overrided method
override func invalidateLayout() {
super.invalidateLayout()
cache.removeAll()
}
I call layout invalidation in my textDidChange delegate
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.characters.count > 0 {
// search and reload data source
self.searchBarActive = true
self.filterContentForSearchText(searchText)
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.reloadData()
}else{
self.searchBarActive = false
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.reloadData()
}
}