Create UICollectiionViewCell based on UIView - objective-c

I am trying to have a UICollectionView that holds different UIViews as its cells. Is this possible or do I have to make them UICollectionViewCells?

I don't have an objective-c example, but you should be able to get the concept from the code example below.
An example how you can create a cell that wraps a UIView and is more reusable
class ProfileView: UIView {
var imageView: UIImageView!
var name: UILabel!
}
class ProfileCollectionViewCell: UICollectionViewCell {
let profileView = ProfileView()
init() {
super.init()
configureConstraints()
}
func configureConstraints() {
// use a handy extension you've already built
contentView.addSubView(profileView)
profileView.pinToEdges(of: contentView)
}
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let row = self.objects[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "someId" for: indexPath) as? ProfileCollectionViewCell
cell?.profileView.imageView.image = row["image"]
cell?.profileView.name.text = row["name"]
return cell
}
note: you may need to manage 'resetting the cells state' before it gets reused with something like:
override prepareForReuse() {
super.prepareForReuse()
profileView.imageView.image = nil
profileView.name.text = ""
}

You have to return UICollectionViewCells. UICollectionView don't accept UIViews.
What you can do is create a generic UICollectionViewCell that can embed any UIView.
The reason is because collection view cells have specific composition for layout and recycling.
Also, you add child in your UIView directly on the view itself, collection view cells have a contentView, like UITableViewCells.

Related

index not being transferred from uicollectionviewcell to view controller

My code below is not working and is causing a runtime error. Stating Unexpectedly found nil while unwrapping an Optional value. I don't know what is causing this. I don't know how to fix the optional issue in this. The code for cellforitemat has also been added.
class antion : UICollectionViewCell {
#IBOutlet var sam : UILabel!
var deleagete : DataCollectionProtocoe?
var index : IndexPath?
#IBAction func press(){
deleagete?.passData(indx: (index?.row)!)
}
#IBAction func delete(){
deleagete?.deleteData(indx: (index?.row)!)
}
}
extension ViewController : DataCollectionProtocoe {
func passData(indx: Int) {
let vc = storyboard?.instantiateViewController(withIdentifier: "DetailVDC") as? DetailVDC
vc?.name = people[indx].name!
self.navigationController?.pushViewController(vc!, animated: true)
}
func deleteData(indx: Int) {
people.remove(at: indx)
cc.reloadData()
}
}
protocol DataCollectionProtocoe {
func passData(indx:Int)
func deleteData(indx:Int)
}
class DetailVDC: UIViewController {
var name = ""
#IBOutlet var lbl : UILabel!
override func viewDidLoad() {
lbl.text = name
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! antion
cell.index = indexPath
cell.deleagete = self
return cell
}
Based on what little i could understand from your code, it looks like you are creating the UICollectionViewCell instance but not setting any value to the delegate property of the cell.
When you create an instance of the collection view cell in the controller , assign the controller to the delegate property of the cell as follows:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = antion()
cell.delegate = self // assuming the controller is the data source of the collection view
}

TableView is not counting exactly

I pass data(value) from a ViewController to a TableView (see below), but the tableview fill always only the first row. It donĀ“t count. How can I fix it?
The tableview should show every passing data in a new row.
#IBAction func a(sender: UIButton) {
txtBalkenbewehrung = ausgabe.text
performSegueWithIdentifier("transferfile", sender: sender)
}
import UIKit
var txtBalkenbewehrung: String?
class EBTableViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
var rowData = [txtBalkenbewehrung]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.editing = true
self.tableView.reloadData()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return rowData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("textcell",
forIndexPath: indexPath) as! UITableViewCell
// let data = rowData[indexPath.row]
cell.textLabel!.text = rowData[indexPath.row]
return cell
}
`
First, please make sure that you correctly format your code!
The behavior seems coherent, as the data is a an array with a single element, txtBalkenbewehrung
You need to fill the array with more element if you want to display more than one

Segue on DidSelectRowAtIndexPath from Custom DataSource/Delegate Swift

My setup:
`UITableViewController` (ComboViewController)
-> Several Static Cells
-> One Static Cell contains a dynamic `tableView`
I need to use a custom Delegate/DataSource because the dynamic tableView is embedded in the Static TableView within the TableViewController
This custom Delegate/DataSource looks like this:
class DataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
// class variables
override init() {
super.init()
// initialize variables
}
//some data source/ delegate methods like number of rows, cellForRowAtIndexPath
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var indexedCombos: NSDictionary?
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let comboVC: ComboInfoViewController = storyboard.instantiateViewControllerWithIdentifier("ComboInfo") as! ComboInfoViewController
comboVC.doSegue()
}
}
Within ComboViewController I have this:
class ComboInfoViewController: UITableViewController {
func doSegue() {
self.performSegueWithIdentifier("tosingle", sender: combListTable)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "tosingle" {
//do stuff
}
}
}
If the segue is modal I get this error:
Warning: Attempt to present SingleProductViewController on ComboInfoViewController whose view is not in the window hierarchy!
If the segue is push, then the prepareForSegue method gets called, but the viewController does not push! What is happening?
I've searched and searched. But I have no idea what could be resulting in this behavior.
When you create the ComboInfoViewController instance with this line,
let comboVC: ComboInfoViewController = storyboard.instantiateViewControllerWithIdentifier("ComboInfo") as! ComboInfoViewController
You're creating a new instance that is not the one you have on screen, and never will be, so that's why you get the error. It is very important that you understand this concept; understanding how view controllers are created, and how to get pointers to ones that already exist is fundamental to iOS programming.
However, in this case you don't even need to get a pointer to the one on screen, because you should connect the segue directly from the cell (the dynamic prototype), which means you won't need any code to execute it. You can delete the didSelectRowAtIndexPath method, and the doSegue method. You only need to implement prepareForSegue. If you need to pass information to the next controller based one which row was touched, you can do it like below. The table view controller code should now look like this (this is an update of the code in my answer to this question, Swift: TableView within Static UITableViewCell),
class ComboInfoViewController: UITableViewController {
#IBOutlet weak var staticTableView: UITableView!
#IBOutlet weak var dynamicTableView: UITableView!
var dataSource = DataSource()
override func viewDidLoad() {
super.viewDidLoad()
dynamicTableView.dataSource = dataSource
dynamicTableView.delegate = dataSource
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row != 1 {
return 44
}else{
return 250 // the second cell has the dynamic table view in it
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "tosingle" {
var cell = sender as! UITableViewCell
var indexPath = dynamicTableView.indexPathForCell(cell)
var dataPoint = dataSource.theData[indexPath!.row] // theData is the array used to populate the dynamic table view in the DataSource class
// pass dataPoint to the next view controller which you get from segue.destinationviewController
println(dataPoint)
}
}
}

Pass Data to next ViewController Using UIBarButtonItem in Swift

I have a UITableView that allows multiple selections. I'd like to pass the selections to the next "Q2ViewController" when user clicks the rightBarButtonItem "Next".
Note: I'm not using Storyboard. After searching through, I haven't found a solution without using storybaord.
var options = ["breakfast", "lunch", "dinner", "dessert"]
var selected = -1
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Q1View"
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next", style: .Done, target: self, action: "didTapNext:")
self.tableView.allowsMultipleSelection = true
var nib = UINib(nibName: "OptionCell", bundle: nil)
tableView?.registerNib(nib, forCellReuseIdentifier: "OptionCellIdentifier")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.options.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("OptionCellIdentifier", forIndexPath: indexPath) as OptionCell
cell.textLabel?.text = self.options[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
}
}
Anywhere in your code you must create the "next" view controller. Either in your App Delegate or directly in the view controller shown above.
If you create the view controller outside the above one you will have to pass the above controller a reference to the destination view controller.
If you create the view controller inside the above one save a reference to it in an instance variable.
Or create a method that creates the VC on pressing the "Next" button and pushes the VC to the navigation controller.
You can use UITableView's indexPathsForSelectedRows() or similar to get the selection and then call a method/set a instance variable on the destination view controller.
But seriously, why don't you use storyboards?

Using a Table View in a View Controller and wiring it up

I'm fairly new to xcode and Objective-C. Here is my problem:
I have a view controller with buttons and links to other view controllers on it.
On this view controller I have added a table view in which the cells will be used like a form
the cells will have text fields and labels
When trying to set this up and building it, it gives me an error saying I need to wire up my table view to the view controller somehow.
I know it is something to do with the data source and the table view delegate but I don't know how to wire the table view to the data source and delegate of my view controller.
Could anyone tell me how, or link me to an easy to follow guide on this?
Thanks
The easiest way would be to create a new Swift, or Objective-C Class and extend UITableViewController with it. This will create you a perfect sample code on how to write a UITableView DataSource and Delegate, which could be just copied.
After that, set your UITableViews delegate and datasource properties to self in viewdidload and implement UITableViewDataSource, UITableViewDelegate.
Edit
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var myTable: UITableView!
var myDataArray: NSArray!
override func viewDidLoad() {
super.viewDidLoad()
myDataArray = NSArray(objects: "Peter", "Paul", "Marry")
myTable.dataSource = self
myTable.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: TableView DataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myDataArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if (cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell?.textLabel.text = myDataArray.objectAtIndex(indexPath.row) as NSString
return cell!
}
//MARK: TableView Delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
I quickly wired you up some Swift Example code, where you can see how to connect a table view, with the DataSource and Delegate of your Class.