I have an array of UIImageViews that I want to display to the screen. However, I can't seem to be able to do so. I declared my array of UIImageViews like so:
class EventCell: UITableViewCell, CellDelegate{
#IBOutlet var eventName: UILabel!
#IBOutlet var eventLocation: UILabel!
#IBOutlet var attendeesImages: [UIImageView]!
}
And I have a function that displays the EventCell contents like so:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Dequeue a "reusable" cell
let cell = tableView.dequeueReusableCellWithIdentifier(eventCellIdentifier) as! EventCell
setCellContents(cell, indexPath: indexPath)
return cell
}
//Set contents of Event Cell.. self.events is a global array
//which have information that EventCell objects need to display
func setCellContents(cell:EventCell, indexPath: NSIndexPath!){
let item = self.events[indexPath.section]
var count = 0
cell.eventName.text = item.eventName()
cell.eventLocation.text = item.eventLocation()
cell.attendeesImage.removeAll(keepCapacity: false)//Remove old images before adding new
for value in item.attendeesImage {
let newImageView = UIImageView(image : value)
newImageView.clipsToBounds = true
newImageView.layer.cornerRadius = newImageView.frame.size.width / 2
cell.attendeesImage.append(newImageView)
println("Count inside: \(cell.attendeesImage.count)")
}
}
I printed out the count of the cell.attendeesImage to ensure that no extraneous images were being added and it seemed to prove correct. However, I have no idea why my images are not displaying. I made sure to hook the cell.attendeesImage as an IBCollection in my Storyboard (since it is an Array) in my EventCell. Any ideas for why this isn't showing up? Thanks!
You are using wrong the collection outlet "attendeesImages".
When the view is loaded, the array attendeesImages are created and initialized with the image views you have created in interface builder. But then, if you remove all that references, you have lost the link between the outlets and the real views. The new image views you are creating are not the ones in the cell. They are still subviews of the cell, but now you have not a iboutlet references to them.
The solution: don't remove the values from the array. Just modify the image in each image view.
Related
Problem I want to allow users to hit 'swap' in a table cell and then find a different Realm object to populate the 2 text labels (for exercise name and number of reps) in the cell with the values from the new object.
Research There's quite a bit (admittedly old) on 'moving rows' (e.g. here How to swap two custom cells with one another in tableview?) and also here (UITableView swap cells) and then there's obviously a lot on reloading data in itself but I can't find anything on this use case.
What have I tried my code below works fine for retrieving a new object. i.e. there's some data in the cell, then when you hit the 'swapButton' it goes grabs another one ready to put in the tableView. I know how to reload data generally but not within one particular cell in situ (the cell that the particular swap button belongs to... each cell has a 'swap button').
I'm guessing I need to somehow find the indexRow of the 'swapButton' and then access the cell properties of that particular cell but not sure where to start (I've played around with quite a few different variants but I'm just guessing so it's not working!)
class WorkoutCell : UITableViewCell {
#IBOutlet weak var exerciseName: UILabel!
#IBOutlet weak var repsNumber: UILabel!
#IBAction func swapButtonPressed(_ sender: Any) {
swapExercise()
}
func swapExercise() {
let realmExercisePool = realm.objects(ExerciseGeneratorObject.self)
func generateExercise() -> WorkoutExercise {
let index = Int(arc4random_uniform(UInt32(realmExercisePool.count)))
return realmExercisePool[index].generateExercise()
}
}
//do something here like cell.workoutName
//= swapExercise[indexRow].generateExercise().name???
}
Hold your objects somewhere in a VC that shows UITableView. Then add the VC as the target to swap button. Implement swapping objects on button press and reload data of table view after.
The whole idea is to move logic to view controller, not in separate cell.
There are 2 ways.
1. Adding VS as button action target.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ... // get cell and configure it
cell.swapBtn.addTarget(self, action: #selector(swapTapped(_:)), for: .touchUpInside)
return cell
}
func swapTapped(_ button: UIButton) {
let buttonPosition = button.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!
// find object at that index path
// swap it with another
self.tableView.reloadData()
}
Make VC to be delegate of cell. More code. Here you create protocol in cell and add delegate variable. Then when you create cell you assign to VC as delegate for cell:
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ... // get cell and configure it
cell.delegate = self
return cell
}
func swapTappedForCell(_ cell: SwapCell) {
// the same logic for swapping
}
Solution from OP I adapted the code here How to access the content of a custom cell in swift using button tag?
Using delegates and protocols is the most sustainable way to achieve this I think.
I hope this helps others with the same problem!
I have been trying to develop a view controller with multiple charts(bar chart, line chart, pie chart). I created a table view and custom table view cell. There is a UIView inside custom table view cell. However, when I am trying to cast that UIView to BarchartView it gives me an error
Could not cast value of type 'UIView' (0x10a8e7f40) to 'Charts.LineChartView' (0x1074f63a0).
How can I achieve that multiple charts in same table view? Thanks in advance.
cellForRowAt indexPath:
let cell = myTableView.dequeueReusableCell(withIdentifier: "chart") as? GraphicCell
var lineChart:LineChartView = cell?.chart as! LineChartView
lineChart.noDataText = "A"
return cell!
the view outlet that I have created in GraphicCell is UIView type
The charts which are shown depends on the user choice. User can select one bar chart and two line chart or only two line chart without bar chart. I do not understand completely how to achieve this. I have added my project to GitHub project link
You need to create prototype cells for each of the types of charts, which you want to use in your TableView. In each prototype cell you need to put UIView and then change the class of UIView to LineChartView, BarChartView, etc.
Also you need to define your own class for each prototype cell, e.g:
class MyLineChartCell: UITableViewCell {
#IBOutlet weak var lineChartView: LineChartView!
func configure (/* ... */) {
lineChartView.noDataText = "You have no data"
// ...
}
}
.
Use this classes for you prototype cells:
Then in func func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell you could choose which prototype will be used at the moment.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyLineChartCellIdentifier") as! MyLineChartCell
cell.configure(/* Data, Colors, etc. */)
}
if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyBarChartCellIdentifier") as! MyBarChartCell
cell.configure(/* Data, Colors, etc. */)
}
//... some other types of cells
return cell
}
The chartView canĀ“t be of type UIView, it has to have the correct type when you declare it. You can have 3 different views inside the tableView cell, like this:
#IBOutlet weak var barChart: BarChartView!
#IBOutlet weak var pieChart: PieChartView!
#IBOutlet weak var lineChart: LineChartView!
and then use the one you need, depending on which graph type you want. If you are using Storyboard, you also need to choose class for each view as BarChartView, LineChartView or PieChartView in the Storyboard.
I have a custom cell class called CurrentFilesCell with the setting code below
class CurrentFileCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var statusImage: UIImageView!
var currentContent: AircraftContent! {
didSet{
setStyles(Constants.appStyleSetting)
nameLabel.text = currentContent.contentName
dateLabel.text = currentContent.contentStatus
}
}
Within my CurrentFilesViewController I simply set it within cellForRowAtIndexPath
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CurrentFileCell", forIndexPath: indexPath) as? CurrentFileCell
cell?.currentContent = content
return cell!
}
I believe I also have everything linked correctly, as I have done something similar to this in other classes, both with cells and vc's.
My problem is that It does not load anything when run, there is no default text and no updated text after it should have been set. Here is an image showing the linkage
http://imgur.com/qlK4d5O
I'm really not sure what is going on and why this isn't working. I have tried deleting it and recreating but I must be missing something.
EDIT
Here is a picture of the debugger showing that the cell's currentContent is not empty. This is taken right before the return cell! is executed.
http://imgur.com/O250qXq
Did you register this cell in table view? If not than dqueRqusableCellWithIdentifier will return nil value...
You can register it using UITableView function "registerNib: forCellReuseIdentifier:"
In the storyboard, you must define subclass of the prototype table cell.
And then, you must define identifier of the prototype table cell as "CurrentFileCell".
Then you will show the content of the table when the app will be run.
I'm trying to put images into my UITableView. The Table is set up with a custom subclass cell. In the Subclass I have outlets:
#IBOutlet var titleLabel: UILabel!
`#IBOutlet var pillarIcon: UIImageView!`
In the Superclass I created a NSMutableArray for both:
var objects: NSMutableArray! = NSMutableArray()
var imageObjects: NSMutableArray! = NSMutableArray()
I place things into the Arrays within the viewDidLoad Method Each array has 4 items.
So when I call the Items:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.objects.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
cell.titleLabel.text = self.objects.objectAtIndex(indexPath.row) as? String
cell.pillarIcon.image = self.imageObjects.objectAtIndex(indexPath.row) as? UIImage
return cell
}
The cell.titleLabel.text items come up but the images in the cell.pillarIcon.image do not come show up in the table.
I have been working on this for a couple hours now and am going in circles it feels like. Also the image files have been loaded into the main file so that is not the problem.
Thanks in advance.
Make sure that your images are loaded into your Images.xcassets and then use the UIImage(name:) method to load the images.
Currently, you are loading your images into your imageObjects array as follows:
self.imageObjects.addObject("book.jpg")
You are not using the UIImage to load the image.
Once your images are a part of your project's image assets (Images.xcassets), load your images like so:
self.imageObjects.addObject(UIImage(named: "book"))
(The above example assumes that book is the name of the image asset group.)
Note, this Adding Image Assets web page has instructions on how to set up an image asset group.
It seems like you are loading images incorrectly, like #whyceewhite said in his answer.
I will try to make it clear to you:
open Assets.xcassets
Drop all images you want to use under AppIcon
Add images to your array this way:
imageObjects.addObject(UIImage(named: "whiteboardapp")!)
Use the same name displayed on Assets.xcassets folder
So, I created a custom table view cell with a label on the left and a UIImageView on the right.
The label has a tag of 100 and the UIImageView a tag of 110.
My code is the following:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("ThemeCell") as UITableViewCell
let theme = themes[indexPath.row]
var themeName = cell.viewWithTag(100) as? UILabel
themeName?.text = theme.themeName
let themeImage = cell.viewWithTag(110) as? UIImageView
themeImage?.image = UIImage(named: "test.png")
//1
//cell.imageView?.image = UIImage(named: "test.png")
println("The loaded image: \(themeImage?.image)")
return cell;
}
As is is, the themeName is displayed but the themeImage does not appear, although from println it seems that the image is loaded. If I uncomment the code in 1 the image appears in the custom cell but of course does not appear in the proper place as it is not added to the UIImageView that I created in IB.
Any ideas what I might be doing wrong? The Tags are all correct.
Thanks
Firstly, you need to pin your views with auto layout mechanism. Open interface builder, left click on label inside your custom cell, then for example do the following:
Editor->Pin->Width
Editor->Pin->Height
Editor->Pin->Leading Space to Superview
Editor->Pin->Top Space to Superview
the same for image inside your custom cell
Editor->Pin->Width
Editor->Pin->Height
Editor->Pin->Trailing Space to Superview
Editor->Pin->Top Space to Superview
Then create custom class for your cell. for example
MyCustomCell.swift
import Foundation
import UIKit
class MyCustomCell: UITableViewCell {
#IBOutlet weak var myLabel: UILabel!
#IBOutlet weak var myImageView: UIImageView!
}
Then set custom class for your cell and create connections from elements.
And now in tableViewController you can set the values to your elements without tags:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: MyCustomCell = tableView.dequeueReusableCellWithIdentifier("ThemeCell") as MyCustomCell
let theme = themes[indexPath.row]
cell.myLabel.text = theme.themeName
cell.myImageView.image = UIImage(named: "test.png")
println("The loaded image: \(cell.myImageView.image)")
return cell;
}
Ok, so the fault was not in the UITable at all but in the fact that the AutoLayout was not set correctly and the image appeared outside the tableview...