How to add a cell with two buttons - ios

I am trying to have two buttons as the first row and the rest of the rows as it is shown in the following picture (I apologize for the flipped picture):
I know how to put two buttons in a cell, like so:
And use the following code to add the first cell to my tableview like so:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
//Configure the first cell with the two buttons
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = cathyList[indexPath.row]
}
return cell
}
My logic allows me to have two buttons as the first row cell but I don't know how to make the buttons big and square like the ones that are shown here. Any suggestions?

You format your button as what you want on Storyboard. I suggest 2 options you can get this:
You can add image and title on button and use Edge property to achieve this. Look at this:
This way is hard to achieve what you need, you have to make sure your icon has the right size, and it's not dynamic.
The second way is easier and more dynamic. But maybe not the best solution. I usually use this way.
You add an image (show your icon), a label (your title) and embed them in a view. Then add a button stretch all the view. Connect this button to action and use it as usual.
Hope this help.

Related

How to left/right-align custom UITableView cell

I’m coding a “chatbot” app, and to hold the message bubbles I have a UITableView and a custom message-bubble shaped cell. Here’s what it looks like so far:
All the cells will look the same, except I’d like every other cell to be, say, half the width of the table and alternating right/left aligned. How could I do this programmatically?
The better way - to create two classes InMessageCell, OutMessageCell, and add all properties (like aligning of all elements) hide inside of this cell. Both cell will have the same width, but all bubbles will be moved on one or other side. It may inheritance from the main class MessageCell, so all logic may stay in main class, but UI part - splitted up.
Two straightforward ways of achieving this by using custom table view cells:
Have two different cell classes. They can share much of their implementation (e.g. by class heritage), but differ in their layout (one is left aligned, one right aligned). For each row in your table, decide which cell you need to use, and dequeue the appropriate one.
Have one cell class whose layout can be toggled when it's being dequeued. (How exactly this toggle looks like depends of course on how you chose to layout your cell. It could e.g. be that you exchange the constant to an autolayout constraint you reference via #IBOutlet, the switching of a background image, or changing the alignment property of a stack view, among many others.)
Both ways depend on making a decision which cell flavor to use in your UITableViewDataSource's tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) function.
Here is a slightly abstract example using the first method. In your UITableViewDataSource:
enum ChatCellAlignment {
case left
case right
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellAlignment: ChatCellAlignment = self.cellAlignmentForIndexPath(indexPath) // you need to implement something like this
var identifier = "Default"
switch cellAlignment {
case .left:
identifier = "LeftAlignedBubbleCell"
case .right:
identifier = "RightAlignedBubbleCell"
}
let cell = self.tableView.dequeueReusableCell(withIdentifier: identifier)
if let cell = cell as? ChatBubbleCell { // assuming your custom cell classes all inherit from a "ChatBubbleCell"
cell.set(text: self.textForIndexPath(indexPath))
... // whatever setup you need to do on your custom cell
}
return cell
}
You can give the table view cell a value to know it. Then you can use autolayout (SnapKit) to make it align left or right

Can I use a single custom cell for multiple different cells?

I have created a single prototype cell which has two labels (mainLabel and subLabel) and an uiimageview. In the uitableview I'd like to have several cells which reuse the prototype and when needed the subLabel is hidden and the uiimageview is changed with different one or with a uiswitch. The two labels have different text for each cell. Do you have any suggestions/hints in order to do it? possibly in a mvvm architecture?
I'll describe what I am doing:
I have a struct (the Model) with two properties: label and sublabel. This is then instantiate by a viewModel which provides text for each cell, done by a method called getModel(_ indexPath: IndexPath) -> cellModel { ... }. Finally in UIViewController, in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) { ... } I am calling getModel(), using dequeueReusableCell and setting up each cell.
In getModel() there is a huuuuge switch which I use to know which cell is which
Then in uitableviewcell I have some method that hides sublabel and changes uiimageview.
It kind of works, however I have some issues with while scrolling. For example, sometimes a uiimageview is drawn in another cell, or a subLabel is hidden, even if it is not supposed to. I guess this is due because it is reusing the cell, and I am not resetting it.
Anyway, any suggestions or ideas?
I know this is overkilling...
No need for any pattern. Yes, you can use that single cell design for all cells. Just hide/empty label(s) and image view as you like per cell.
First of all you have to set default value to both the labels and imageview
i.e. (consider a title label, a sub label and a imageview)
lblTitle.isHidden = false
lblSubLabel.isHidden = false
imgViewIcon.image = nil
Then just show labels in specific condition that you want to match and set image in imageview
i.e. (consider your condition to hide sub label)
if needToHide == true {
lblSubLabel.isHidden = true
}

How to set the topmost cell (first row) of detail view's table view with master view's selected cell content?

Working on a social iPhone app using Swift (with a Storyboard) and Parse where users can create posts and comment on posts similar to the Facebook iOS app and other social network apps.
The app has an initial, master Home Feed page (which displays user posts) and a detail Reply page (which displays user comments). Both use the PFTableViewController class and each of those table views have their own PFTableViewCell implemented in separate swift files as the prototype cells.
I am trying to send the content (username, post message, timestamp, etc) of a selected post cell from the master Home Feed page to the detail Reply page's topmost cell (the first cell at the top of the table view).
My goal is to have it work similar to the way the Facebook, Instagram, and Twitter iOS apps have it - whenever a user selects a post in the main feed/timeline, the detail view is shown where the main post is at the top (but not pinned to the top - meaning it will scroll up/down with the tableview) and its comments are in the cells beneath it.
I appreciate your help and time! Thank you!
On Selection on left panel, you can make tableview on right panel scroll to top animated false.
After further research, one way to "hack" it is by doing something similar to the following:
1) Create a custom tableview cell for the top row (topmost cell) by implementing it in a separate Swift file, just as you may have done for the prototype cell.
2) Now you have two custom cells. So implement two function where in each you customize them the way that serves your apps requirements, etc and the cell.
3) In the cellForRowAtIndexPath method, use an if/else statement to return the appropriate tableview cell for row 0 (topmost/header cell), otherwise return the other prototype cell for any other row (i.e.: the cells beneath the header cell):
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
return headerCellAtIndexPath()
} else {
return commentCellAtIndexPath(indexPath)
}
}
func headerCellAtIndexPath() -> CommentsHeaderTableViewCell {
let headerCell = tableView.dequeueReusableCellWithIdentifier("topCell") as! CommentsHeaderTableViewCell
// Customize your headerCell...
return headerCell
}
func commentCellAtIndexPath(indexPath:NSIndexPath ) -> CommentTableViewCell {
let commentCell = tableView.dequeueReusableCellWithIdentifier("commentCell", forIndexPath: indexPath) as! CommentTableViewCell
// Customize your commentCell...
return commentCell
}

TableViewCell button click firing in multiple sections of TableViewControl

Bit of a weird one i can't seem to understand so i have a tableview control in a viewcontroller and within the tableviewcell i have a button which is using a delegate.
So when the button is clicked it will change the tag number of the cell and also change the image of the button based on the tag of the cell in the tableview.
But the problem i'm having is that when you select a button in a row i.e. the first one it seems to be running the function to change the image for each item in a section almost. I.e choosing the 5th item will update every 5th button in a cell to the selected image which is weird. Since it's almost like the tableview is being split up to sections of 5.
Can anyone help prevent this behaviour so it only changes the icon for the button in the cell which has been pressed.
Below are the functions that i've used and a link to a video on dropbox showing the behaviour https://www.dropbox.com/s/a4aasti78872w6j/Help.mov?dl=0
Delegate
protocol StoryTableViewCellDelegate: class {
func didBookmarkItem(cell: StoryTableViewCell, sender: AnyObject)
}
Function for Delegate
#IBAction func bookmarkButtonDidTouch(sender: AnyObject) {
bookmarkButton.animation = "pop"
bookmarkButton.curve = "easeOut"
bookmarkButton.duration = 0.5
bookmarkButton.damping = 0.4
bookmarkButton.velocity = 0.4
bookmarkButton.animate()
// The delegate which will handle bookmarking items
delegate?.didBookmarkItem(self, sender: sender)
}
Function being used in tableview class
// MARK: StoryTableViewDelegate
func didBookmarkItem(cell: StoryTableViewCell, sender: AnyObject) {
// TODO: Implement bookmark functionality
switch cell.bookmarkButton.tag {
case 0:
cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Selected"), forState: UIControlState.Normal)
cell.bookmarkButton.tag = 1
case 1:
cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Not-Selected"), forState: UIControlState.Normal)
cell.bookmarkButton.tag = 0
default:
break
}
}
The reason is, you are probable creating a cell using :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellID")
...
like you should do. However dequeueReusableCellWithIdentifier re-uses a cell, so if you have changed anything in a cell (like adding buttons), those buttons will still be in that recycled cell.
So you must set the book mark status in your cellForRowAtIndexPath for each cell.
I once had a similar problem when adding buttons to a cell, and when scrolling the cells automatically had extra buttons. So the first thing I did when re-using a cell was remove all buttons.
Edit sample code
in your
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
you have to add code for setting the button to the desired state, it will be something similar to the code you're using in didBookMarkItem :
switch myProperty {
case 0:
cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Selected"), forState: UIControlState.Normal)
cell.bookmarkButton.tag = 1
case 1:
cell.bookmarkButton.setImage(UIImage(named: "Bookmark-Not-Selected"), forState: UIControlState.Normal)
cell.bookmarkButton.tag = 0
default:
break
}
You'll need a myProperty variable of course, which you should change in your didBookMarkItem as well
As others have said, it's due to table cell reuse. You want your tableView(_:cellForRowAtIndexPath:) method to always update the cell state from your model. Your bookmark state should be a property of your model. When the bookmark button state for a cell is changed by the user, the new state should be reflected in your model. If you do these things, your table cell state will always be correct. If you don't already, it's nice to always define a custom UITableViewCell class that contains outlets for all of the views and controls within your table view cell (your bookmark button would have an outlet.) Also, within your custom cell class, when you capture the button selection, you can call back to the controller either via a delegate (as you are doing), or a "bookmarkChanged" handler (closure) defined on the cell. I prefer the closure method. If you would like to see an working example of this, let me know.
Also, nix the tag. You don't need the tag to keep track of your bookmark button selection state, unless there's more to it than you have shown/described. If you follow the approach I described, it's taken care of.
Table view cells are reused. Once you select a cell and change its tag number and scroll the selected cell out of the table view, it will be used again to show a row at the index path of the new row that appears. And since its tag represents that of a selected cell it is displayed as highlighted.
Try to look up about cell reuse in table views.
You need to change your approach about determining which cell is to be displayed as selected. Add it as a property in your data source and based on that set the bookmark as selected or not selected.

swift toggle between different table view cell layouts

I wonder what techniques there are when it comes to toggle between different layouts in a table view.
What I have right now is an embedded tableview/custom cell inside my VC.
It has a simple list design, an image / title.
What I would like to do is when the user press the "grid" button it will change the layout into a bigger cell, kinda like how instagram looks.
So is it possible to animate between different cell layouts in a tableview?
thanks!
I don't believe that it's possible to change the style once it has been initialised. You can however change between your own custom cells at runtime and is probably best achieved using a protocol for different cell types.
Yes it is possible. I have used it but I am not saying that this is the ultimate way.
Here are the steps you may like to follow :
Design two different cells with different identifiers(I did it from storyboard)
In cellForRowAtIndexPath method, check for the identifiers and display the layouts accordingly.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = (self.layoutSegmentControl.selectedSegmentIndex == 0) ? "gridLayoutCell" : "listLayoutCell" //I used segment control to toggle, change the condition as per your need
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! MyCustomTableViewCell
if(cellIdentifier == "gridLayoutCell")
{
//Set the values
cell.bigImgView.image = [yourimage] //for ex
...
}
if(cellIdentifier == "listLayoutCell")
{
//Set the values
cell.thumbnailImgView.image = [yourimage] //for ex
...
}
}
reload your tableview when toggling(layout changes)
Try this and let me know. Hope it works for you!

Resources