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
}
Related
I have two View Controller. The first one is MyListOfTasksVC and the second one is AddAndEditVC. In the second VC i have a date picker and pass date to subtitle lable in cellForRowAt. Before implementing that my Done button was disabled if textField is empty. But now datePicker ignores that and adds new row with just date.
How I can disable Done button in such situation? I tried to make delegate, but it wasn't successful.
//in MyListOfTasksVC
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyDailyTasksCell", for: indexPath)
let item = items[indexPath.row]
configureText(for: cell, with: item)
configureCheckmark(for: cell, with: item)
let date = items[indexPath.row].date
let formatter = DateFormatter()
formatter.dateFormat = "MMM d, h:mm a"
cell.detailTextLabel?.text = formatter.string(from: date)
return cell
}
It looks like what you're trying to build is a todo-list app that prevents the user from entering a task item without a title.
Your first view controller, MyListOfTasksVC, displays all the tasks which have already been added.
Your second view controller, AddAndEditVC, has a UITextField for entering a new task's title and a UIDatePicker to set a deadline for the task. Somewhere on the second view controller, there is a 'DONE' button that creates an Item struct with the text from the UITextField as the .title property and the date from the UIDatePicker as the .date property. This struct then gets passed back to MyListOfTasksVC and appended to the array items, and is displayed as another task in the UITableView.
The question you're asking seems to be, "How to disable this button if the value of textField.text is nil or the empty string?"
The simplest way I know of is to set the 'DONE' button's isEnabled property inside your UITextFieldDelegate method textFieldDidEndEditing. If the value of your text field's text is nil or "", set doneButton.isEnabled = false. Otherwise, doneButton.isEnabled = true. This way, the button only allows submitting the new task if it has a title.
Here is what I had inside AddAndEditVC:
import UIKit
class AddAndEditVC: UIViewController {
#IBOutlet weak var taskNameField: UITextField!
#IBOutlet weak var datePicker: UIDatePicker!
#IBOutlet weak var doneButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
doneButton.isEnabled = false
taskNameField.delegate = self
}
#IBAction func addNewTask(_ sender: UIButton) {
self.performSegue(withIdentifier: "backToTasksList", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let newItem = Item(title: taskNameField.text!, date: datePicker.date)
let destinationVC = segue.destination as! MyListOfTasksVC
destinationVC.newItem = newItem
}
}
extension AddAndEditVC: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.endEditing(true)
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField.text != nil && textField.text != "" {
doneButton.isEnabled = true
} else {
doneButton.isEnabled = false
}
}
}
and here is MyListOfTasksVC:
import UIKit
struct Item {
var title: String
var date: Date
}
class MyListOfTasksVC: UIViewController {
#IBOutlet weak var tasksTable: UITableView!
var newItem: Item?
var items: [Item] = [Item(title: "Wake Up", date: Date()), Item(title: "Feed Dog", date: Date()), Item(title: "Finish Report", date: Date())]
override func viewDidLoad() {
super.viewDidLoad()
tasksTable.dataSource = self
if newItem != nil {
items.append(newItem!)
}
}
#IBAction func toAddAndEditScreen(_ sender: UIButton) {
self.performSegue(withIdentifier: "toAddAndEdit", sender: self)
}
}
extension MyListOfTasksVC: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyDailyTasksCell", for: indexPath)
let item = items[indexPath.row]
//configureText(for: cell, with: item)
//configureCheckmark(for: cell, with: item)
cell.textLabel?.text = item.title
let date = items[indexPath.row].date
let formatter = DateFormatter()
formatter.dateFormat = "MMM d, h:mm a"
cell.detailTextLabel?.text = formatter.string(from: date)
return cell
}
}
Is this the functionality you're looking for?
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
}
}
I am using SideMenu and I am trying to add an item to that SideMenu from another View Controller.
I store the items for SideMenu in habits object. But I have no idea how to add a new item from ADD VIEW CONTROLLER as there is no segue.
To sum up;
How can I access/edit habits object in SideMenu from "Add View Controller"
Here is my code for SideMenu;
import UIKit
import SideMenu
import FSCalendar
class MenuListController: UITableViewController {
var habits = [Habit]()
var selectedHabitIndex = 0
let darkColor = UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1)
override func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
tableView.backgroundColor = darkColor
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// MARK: - HABIT INITILIZAR
var dateStrings = ["2020-12-25","2020-12-24","2020-12-23","2020-12-22"]
var dateObjects = [Date]()
let dateFormatter = DateFormatter()
for date in dateStrings{
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateObject = dateFormatter.date(from: date)
dateObjects.append(dateObject!)
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
let someDate = formatter.date(from: "2020/12/29")
habits = [Habit(name: "Read a book", selectedDatesArray: dateObjects),
Habit(name: "Go for a walk", selectedDatesArray: dateObjects)
]
}
// MARK: - Number of Habits in the Table View
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return habits.count
}
// MARK: - Display Names of the Habits in the Table View
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = habits[indexPath.row].name
cell.textLabel?.textColor = .white
cell.backgroundColor = darkColor
return cell
}
}
Main View Controller
import UIKit
import SideMenu
import FSCalendar
class ViewController: UIViewController, FSCalendarDelegate, FSCalendarDelegateAppearance {
var selectedDateArray : [Date] = []
var habits = [Habit]()
var menu: SideMenuNavigationController?
var selectedHabit: Habit?
#IBOutlet weak var calendar: FSCalendar!
var selectedDate = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
calendar.delegate = self
calendar.scrollDirection = .vertical
calendar.allowsMultipleSelection = true
calendar.locale = NSLocale(localeIdentifier: "tr") as Locale
menu = SideMenuNavigationController(rootViewController: MenuListController())
menu?.leftSide = true
menu?.setNavigationBarHidden(true, animated: false)
SideMenuManager.default.leftMenuNavigationController = menu
SideMenuManager.default.addPanGestureToPresent(toView: self.view)
var dateStrings = ["2020-12-25","2020-12-24","2020-12-23","2020-12-22"]
var dateObjects = [Date]()
let dateFormatter = DateFormatter()
for date in dateStrings{
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateObject = dateFormatter.date(from: date)
dateObjects.append(dateObject!)
}
habits = [Habit(name: "Read a book", selectedDatesArray: dateObjects),
Habit(name: "Go for a walk", selectedDatesArray: dateObjects)
]
}
func toggleSideBar() {
present(menu!, animated: true, completion: nil)
}
#IBAction func didMenuTapped(_ sender: UIButton) {
present(menu!, animated: true, completion: nil)
}
func showSelectedDates (habit: Habit) {
calendar.select(habit.selectedDatesArray)
}
func setTitle(habit: Habit) {
title = habit.name
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
selectedDateArray.append(date)
}
func updateUI() {
setTitle(habit: selectedHabit ?? habits[0] )
showSelectedDates(habit: selectedHabit ?? habits[0])
}
}
Add Habit View Controller
import UIKit
class AddHabitViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addbuttonTapped(_ sender: UIButton) {
// NO IDEA WHAT TO PUT HERE?
self.dismiss(animated: true, completion: nil)
}
}
protocol MenuVCDataFillDelegate : class {
func addNewData(data: Habit)
}
class MenuListController : UITableViewController,MenuVCDataFillDelegate {
func addNewData(data: Habit){
habits.append(data)
}
}
Then, define your main ViewController like this:
class ViewController : UIViewController, AddHabitDelegate {
weak var menuDelegate : MenuVCDataFillDelegate?
func addMenuVC(){
let vc = MenuListController()
self.menuDelegate = vc
}
func navigateToAddHabit(){
let vc = AddHabitViewController()
vc.delegate = self
}
func newHabitAdded(data: Habit){
delegate?.addNewData(data: data)
}
}
And modify your AddHabitViewController to fill this data when added:
protocol AddHabitDelegate : class {
func newHabitAdded(data: Habit)
}
class AddHabitViewController: UIViewController {
weak var delegate : AddHabitDelegate?
func needsAddItem(data: Habit){
delegate?.newHabitAdded(data: data)
}
}
You can use closure or delegates pattern to pass your habit object. Implement the code below by checking, you can use this sample pattern.
// AddHabitViewController
typealias SuccessListener = (Habit) -> ()
var successListener: SuccessListener?
#IBAction func addbuttonTapped(_ sender: UIButton) {
self.dismiss(animated: false, completion: {
passTheHabitObj = Habit(name: "yourString", selectedDatesArray: dateObject)
self.successListener?(passTheHabitObj)
})
}
// ViewController
var habit = [HabitArray]() // use your array for data
let sb = UIStoryboard(name: "Main", bundle: nil)
if let destVC = sb.instantiateViewController(withIdentifier: "AddHabitViewController") as? AddHabitViewController {
destVC.successListener = { habitObj in
habit.append(habitObj)
}
thanks all for the answers. I tried both approaches but could not make it work.
Using the notification center solved my problem;
In AddHabitVC;
NotificationCenter.default.post(name: Notification.Name("ourCustom"), object: textField.text)
In SideMenuVC:
var observer : NSObjectProtocol?
observer = NotificationCenter.default.addObserver(forName: Notification.Name("ourCustom"), object: nil, queue: .main, using: { (notification) in
guard let object = notification.object as? String else {
return
}
self.items.append(object)
self.tableView.reloadData()
})
Thanks.
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)
}
}
}
I'm trying to create a photo album via UIImagePicker into a CollectionView and cannot get it to segue to that same photo again in a detailed UIViewController. Pulling my hair out and this is just a tutorial as I have just started coding!
Can anyone tell me what I'm doing wrong?
Here is my ViewController:
import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate {
#IBOutlet private weak var addButton: UIBarButtonItem!
#IBOutlet private weak var collectionView:UICollectionView!
#IBOutlet private weak var trashButton:UIBarButtonItem!
var testItems = [Person]()
var stormTrooperCollectionArray: [UIImage] = [#imageLiteral(resourceName: "StormTrooper-3052-423a-8c57-7220081e1585_800x"), #imageLiteral(resourceName: "ST3"), #imageLiteral(resourceName: "ST2"), #imageLiteral(resourceName: "ST4")]
#IBAction func addItem() {
addNewPerson()
}
#IBAction func trashItem(_ sender: Any) {
if let selectedItems = collectionView.indexPathsForSelectedItems {
let itemsForDeletion = selectedItems.map{$0.item}.sorted().reversed()
for item in itemsForDeletion {
testItems.remove(at: item)
}
collectionView.deleteItems(at: selectedItems)
}
}
#objc func refresh() {
addItem()
collectionView.refreshControl?.endRefreshing()
}
override func viewDidLoad() {
super.viewDidLoad()
// Set up a 3-column Collection View
let width = (view.frame.size.width - 20) / 3
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width:width, height:width)
// Refresh Control
let refresh = UIRefreshControl()
refresh.addTarget(self, action: #selector(self.refresh), for: UIControlEvents.valueChanged)
collectionView.refreshControl = refresh
// Edit
navigationItem.leftBarButtonItem = editButtonItem
navigationController?.isToolbarHidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "DetailSegue" {
if let dest = segue.destination as? DetailsViewController,
let index = sender as? IndexPath {
dest.detailedImageHi = stormTrooperCollectionArray [index.row]
}
}
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
navigationController?.isToolbarHidden = !editing
addButton.isEnabled = !editing
trashButton.isEnabled = editing
collectionView.allowsMultipleSelection = editing
let indexes = collectionView.indexPathsForVisibleItems
for index in indexes {
let cell = collectionView.cellForItem(at: index) as! CollectionViewCell
cell.isEditing = editing
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UIImagePickerControllerDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return stormTrooperCollectionArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
//cell.titleLabel.text = stormTrooperCollectionArray[indexPath.row]
cell.selectionImage.image = stormTrooperCollectionArray[indexPath.row]
cell.isEditing = isEditing
return cell
}
#objc func addNewPerson() {
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else { return }
let imageName = UUID().uuidString
let imagePicture = getDocumentsDirectory()
if let jpegData = UIImageJPEGRepresentation(image, 80) {
try? jpegData.write(to: imagePicture)
}
//let detailedItem = Person(imageHi: imageName)
//testItems.append(detailedItem)
let detailedItem = Person(imageHi: imageName)
//KEEPS THROWING AN ERROR HERE WHICH SAYS: Cannot convert value of type 'String' to expected argument type 'UIImage'
stormTrooperCollectionArray.append(detailedItem)
collectionView?.reloadData()
dismiss(animated: true)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if !isEditing {
performSegue(withIdentifier: "DetailSegue", sender: indexPath)
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
}
Here is my VC for the Cell in the CollectionView:
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var selectionImage: UIImageView!
}
Here is my VC for the Detailed View Controller:
import UIKit
class DetailsViewController: UIViewController {
var selection: String!
var detailedImageHi: UIImage!
#IBOutlet private weak var detailsLabel: UILabel!
#IBOutlet private weak var detailedImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
detailsLabel.text = selection
detailedImage.image = detailedImageHi
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is my VC for the NSObject Swift File:
import UIKit
class Person: NSObject {
var imageHi: UIImage
init(imageHi: UIImage){
self.imageHi = imageHi
}
}
In your code the UIImage is image and not imageName:
guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else { return }
So all you have to do is pass the right argument to the constructor of Person:
let detailedItem = Person(imageHi: image)
imageName is a random string generated via UUID().uuidString, and used in this code to save the image to the documents directory with a random and unique name.