Text getting overlapped in uitableview cells in iOS swift - ios

I have created a prototype UITableViewCell on storyboard.It contains 1 ImageView, 3 labels to display the content. All the controls have outlets in corresponding subclass of UITableViewCell. I display messages which can be multi line. So I had to add following methods
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
The text of the labels is getting overlapped and it happens whenever I scroll the tableview. It is only happening with either first 2 rows or the last row.But as i searched on google, I found that it can happen on any row any time. Here's my code of the extension which is commonly written.
extension ConversationViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let count = selectedConversation?.msgArrayWithBodyText.count {
return count
}
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(conversationMessageIdentifier, forIndexPath: indexPath) as! ConversationMessageTableViewCell
let currMsg = selectedConversation.msgArrayWithBodyText[indexPath.row]
cell.userFullNameLabel.text = currMsg.senderName
cell.dateLabel.text = selectedConversation.getShortDateForMessage(currMsg.timeSent)
cell.messageBodyLabel.text = currMsg.bodyText //Constants.testString
let imageUrl = "\(Constants.serverUrl)/api/users/\(currMsg.senderId)/profilePicture"
if let item = ImageCache.sharedInstance.objectForKey(imageUrl) as? CacheableItem {
print("\(imageUrl) found in cache, expiresAt: \(item.expiresAt)")
cell.userImageView.image = UIImage(data: item)
} else {
cell.userImageView.image = UIImage(named: "Profile")
self.imageDownLoadingQueue.addOperationWithBlock({
if let url = NSURL(string: imageUrl) {
if let purgableData = NSPurgeableData(contentsOfURL: url) {
if let downloadedImage = UIImage(data: purgableData) {
print("cache: \(imageUrl)")
let item = CacheableItem()
item.setData(purgableData)
ImageCache.sharedInstance.setObject(item, forKey: imageUrl)
NSOperationQueue.mainQueue().addOperationWithBlock({
if let updateCell = tableView.cellForRowAtIndexPath(indexPath) as? ConversationMessageTableViewCell {
updateCell.userImageView.image = downloadedImage
}
})
}
}
}
})
}
//cell.clipsToBounds = true
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if cell.respondsToSelector(Selector("setSeparatorInset:")) {
cell.separatorInset = UIEdgeInsetsZero
}
if cell.respondsToSelector(Selector("setLayoutMargins:")) {
cell.layoutMargins = UIEdgeInsetsZero
}
if cell.respondsToSelector(Selector("setPreservesSuperviewLayoutMargins:")) {
cell.preservesSuperviewLayoutMargins = false
}
cell.backgroundColor = UIColor.clearColor()
cell.backgroundView = UIView(frame:cell.frame)
if(cell.backgroundView?.layer.sublayers?.count > 1){
cell.backgroundView?.layer.sublayers?.removeAtIndex(0)
}
let layer = self.getGradientLayer(indexPath.row)
cell.backgroundView?.layer.insertSublayer(layer, atIndex: 0)
}
}
And here's the subclass of UITableViewCell i have written for the protyped cell.
class ConversationMessageTableViewCell: UITableViewCell {
#IBOutlet weak var userImageView: UIImageView!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var userFullNameLabel: UILabel!
#IBOutlet weak var messageBodyLabel: UILabel!
#IBOutlet weak var messageBodyLabelHeightConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
userImageView.layer.borderColor = UIColor.clearColor().CGColor
userImageView.layer.borderWidth = 1.0
userImageView.layer.cornerRadius = (userImageView.frame.height/2)
userImageView.clipsToBounds = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
Here's the edited screen shot (I have blackened out the name and faces)
Help required!
I can see long text not getting messed up,but it only happens with small texts.
Basically, this only happens when i scroll the tableview up and down few times. All the text is displayed properly when tableview loads, but then messes up and then clears out for a while and again messes up.

I found the solution to this problem.
There is an option in story board which says Clear Graphics Context which basically clears the graphics for the label before redrawing it.

Related

UITableView changing image and title position cell by cell

I was wondering if there any possible way to create a table view with this style:
I have a dictionary contains title and image values, I need to create a cell one Image-Right / Title-Left and next vice versa. How can achieve something like this?
You can do it by setAffineTransform in this way:
• build up your tableView with one prototype cell that has an image in left and a label in right
• then do this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourTableViewCell
if (indexPath.row % 2 == 0) {
cell.contentView.layer.setAffineTransform(CGAffineTransform(scaleX: -1, y: 1))
cell.YourImage.layer.setAffineTransform(CGAffineTransform(scaleX: -1, y: 1))
cell.YourLabel.layer.setAffineTransform(CGAffineTransform(scaleX: -1, y: 1))
}
// do what ever you want ...
return cell
}
also the best solution is defining 2 prototype cells but in your case this is a tricky and fast way to achieve your goal.
Yes, you can use a table view to achieve your requirement. you will need to follow the following steps.
Method 1:
Create two table view cell XIB's one with left side label and right side image, the second one is with left side image and right side image.
Keep same class of both the XIB's you have created but with different identifiers.
In your Table view cellForRowAtIndexPath method implement following logic.
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasourceArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row % 0 == 0) {
let cell = tableView.dequeueReusableCell(withIdentifier: "RightLabelTableViewCell", for: indexPath) as! CustomTablViewCell
cell.model = datasourceArray[indexPath.row]
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "LeftLabelTableViewCell", for: indexPath) as! CustomTablViewCell
cell.model = datasourceArray[indexPath.row]
return cell
}
}
}
Note: You can use one class for TableViewCell with a different
identifier and design your xib's accordingly.
Method 2:
Flip your table view cell's content view in a such a way that they will swap in your UI.
add the following code into your cellForRowAtIndexPath and also add else part of it because cell for a row may behave weirdly because of dequeing:
extension UIView {
/// Flip view horizontally.
func flipX() {
transform = CGAffineTransform(scaleX: -transform.a, y: transform.d)
}
}
Usage:
cell.contentView.flipX()
cell.yourImage.flipX()
cell.youImageName.flipX()
Don't forget to add else part in cellForRowAt method.
There are actually many ways of doing this:
Create 2 cells. Have 2 cells like OddTableViewCell and EvenTableViewCell. You can choose with index path which to use in cellForRow method like:
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row%0 == 0) {
let cell = tableView.dequeueReusableCell(withIdentifier: "EvenTableViewCell", for: indexPath) as! EvenTableViewCell
cell.model = dataArray[indexPath.row]
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "OddTableViewCell", for: indexPath) as! OddTableViewCell
cell.model = dataArray[indexPath.row]
return cell
}
}
}
Have a single cell but duplicate views so you have 2 labels and 2 image views. Then hide them as you need to:
class MyCell: UITableViewCell {
#IBOutlet private var leftImageView: UIImageView?
#IBOutlet private var rightImageView: UIImageView?
#IBOutlet private var leftLabel: UILabel?
#IBOutlet private var rightLabel: UILabel?
var userImage: UIImage? {
didSet {
refresh()
}
}
var userName: String? {
didSet {
refresh()
}
}
var imageOnLeft: Bool = false {
didSet {
refresh()
}
}
func refresh() {
leftImageView?.image = imageOnLeft ? userImage : nil
leftImageView?.isHidden = !imageOnLeft
rightImageView?.image = imageOnLeft ? nil : userImage
rightImageView?.isHidden = imageOnLeft
leftLabel?.text = imageOnLeft ? nil : userName
leftLabel?.isHidden = imageOnLeft
rightLabel?.text = imageOnLeft ? userName : nil
rightLabel?.isHidden = !imageOnLeft
}
}
Have a single cell with stack view. Add a label and image view onto the stack view. You can change order of items in stack view. Some promising answer can be found here. The rest should be pretty similar to the second solution.
(4.) Also you could just use a collection view and have a label cell and an image cell.
Create one cell with 2 image and 2 label left and right
when you went to left side image that time hide right side image same as in label.
cell
import UIKit
class TestTableViewCell: UITableViewCell {
#IBOutlet weak var lbl_left: UILabel!
#IBOutlet weak var lbl_right: UILabel!
#IBOutlet weak var img_right: UIImageView!
#IBOutlet weak var img_left: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func configure_cell(left:Bool)
{
if left{
img_left.isHidden = true
img_right.isHidden = false
lbl_left.isHidden = false
lbl_right.isHidden = true
self.img_right.image = UIImage(named: "testimg")
}else{
img_left.isHidden = false
img_right.isHidden = true
lbl_left.isHidden = true
lbl_right.isHidden = false
self.img_left.image = UIImage(named: "testimg")
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
ViewController
extension ViewController:UITableViewDataSource,UITableViewDelegate
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "TestTableViewCell", for: indexPath) as? TestTableViewCell
if (indexPath.row + 1) % 2 == 0 {
cell?.configure_cell(left: true)
} else {
cell?.configure_cell(left: false)
}
return cell!
}
}

How to make checklist in UITableView - Swift?

I made an app with UITableView. I want to show a tick mark in the left when cell is touched, and to be hidden when again is touched. I used some code and It's not showing as I wanted. The tick is showing on the right not on the left of screen.
This is how I want to make:
This is how it is:
And here is code that I used:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.allowsMultipleSelection = true
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.None
}
In conclusion, first problem is that the tick is showing on the right of the cell and not on the left. And the other problem, it won't untick (hide when cell is pressed again)
Thanks.
Try this
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "DhikrTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! GoalsTableViewCell
cell.tickButton.addTarget(self, action: #selector(GoalsViewController.toggleSelcted(_:)), forControlEvents: UIControlEvents.TouchUpInside)
cell.tickButton.tag = indexPath.row
// Fetches the appropriate meal for the data source layout.
let workout = workouts[indexPath.row]
let number = numbers[indexPath.row]
if workout.isSelected {
cell.tickButton.setImage(UIImage(named: "Ticked Button"), forState: UIControlState.Normal)
} else {
cell.tickButton.setImage(UIImage(named: "Tick Button"), forState: UIControlState.Normal)
}
cell.nameLabel.text = workout.name
cell.numberLabel.text = number.number
return cell
}
func toggleSelcted(button: UIButton) {
let workout = workouts[button.tag]
workout.isSelected = !workout.isSelected
myTableView.reloadData()
}
To achieve this behavior with default UITableViewCell, you may need to set table view to edit mode.
Try the following code in your viewDidLoad.
self.tableView.allowsMultipleSelectionDuringEditing = true
self.tableView.setEditing(true, animated: false)
This will show tick mark on the left side, and also this will untick (hide) when cell is pressed again.
Edited:
If you need more customization, Create a custom table view cell and handle the selection/tick mark manually.
This will be your cell.swift.
class CustomCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var tickImageView: UIImageView!
//Handles the cell selected state
var checked: Bool! {
didSet {
if (self.checked == true) {
self.tickImageView.image = UIImage(named: "CheckBox-Selected")
}else{
self.tickImageView.image = UIImage(named: "CheckBox-Normal")
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
checked = false
self.layoutMargins = UIEdgeInsetsZero
self.separatorInset = UIEdgeInsetsZero
}
The datasource array is,
let list = ["Title 1", "Title 2", "Title 2", "Title 4"]
The view controller didLoad will be like
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
listView.registerNib(UINib(nibName: "OptionsSelectionCell", bundle: nil), forCellReuseIdentifier: "SelectionCell")
}
The view controller table delegate methods will be like,
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SelectionCell") as! OptionsSelectionCell
cell.titleLabel.text = list[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! OptionsSelectionCell
cell.checked = !cell.checked
}
}

Expandable table view cell using auto layout is not working?

I tried to replicate the expandable tableview cells using this tutorial
I will show what I have done and point out what am I missing here?!! I'm stuck here. It would be helpful if you point out the step I miss!!
TableviewController
class ExpandableCell: UITableViewController {
let titles = ["one" , "two"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 125
// tableView.tableFooterView = UIView(frame: CGRectZero)
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableCell
cell.title.text = titles[indexPath.row]
cell.indexPath = indexPath
switch expandedIndexPath {
case .Some(let expandedIndexPath) where expandedIndexPath == indexPath:
cell.showsDetails = true
default:
cell.showsDetails = false
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: false)
switch expandedIndexPath {
case .Some(_) where expandedIndexPath == indexPath:
expandedIndexPath = nil
case .Some(let expandedIndex) where expandedIndex != indexPath:
expandedIndexPath = nil
self.tableView(tableView, didSelectRowAtIndexPath: indexPath)
default:
expandedIndexPath = indexPath
}
}
var expandedIndexPath: NSIndexPath? {
didSet {
switch expandedIndexPath {
case .Some(let index):
tableView.reloadRowsAtIndexPaths([index], withRowAnimation: UITableViewRowAnimation.Automatic)
case .None:
tableView.reloadRowsAtIndexPaths([oldValue!], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
}
}
TableViewCell
class TableCell: UITableViewCell {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var descriptionConstraint: NSLayoutConstraint!
#IBOutlet weak var descriptionNew: UILabel!
// let detailViewDefaultHeight: CGFloat = 44
let lowLayoutPriority: Float = 250
let highLayoutPriority: Float = 999
var showsDetails = false {
didSet {
descriptionConstraint.priority = showsDetails ? lowLayoutPriority : highLayoutPriority
}
}
var indexPath = NSIndexPath()
override func awakeFromNib() {
super.awakeFromNib()
descriptionConstraint.constant = 0
}
}
StoryBoard
This is the output I'm getting which is not the one I'm trying to get,
Base on your code i think are you missing bellowing method :-
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return UITableViewAutomaticDimension
}
Seems like you have set the low and high priority values in the reverse order
var showsDetails = false {
didSet {
descriptionConstraint.constant = showsDetails ? highLayoutPriority: lowLayoutPriority
}
}

Image added to UITableViewCell appears in wrong rows when scrolling

I'm adding an image to a table view row (actually, I seem to be adding it to the row's cell) when selecting it (and removing when selecting it again). The table view consists of prototype cells.
This works but when I scroll around and get back to the row I had previously selected, the image would be in another row. Also, the image appears in other rows as well.
My guess is this happens because the cells are re-used when scrolling.
Here's the code of a little sample project:
import UIKit
class MyTableViewController: UITableViewController {
// Using integers for simplicity, should work with strings, too.
var numbers = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<50 {
numbers.append(i)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath: indexPath)
cell.textLabel?.text = "\(numbers[indexPath.row] + 1)"
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numbers.count
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
if let myImage = curCell.viewWithTag(10) as? MyImage {
myImage.removeFromSuperview()
} else {
let myImage = myImage()
myImage.tag = 10
cell.addSubview(myImage)
}
}
I need to have the image stay in the correct row, also when coming back to this view controller. What's the correct way to tackle this?
Any advice much appreciated!
EDIT: I've tried to implement matt's answer but I seem to be missing something, as the problem is still the same.
EDIT 2: Updated, working as intended now.
import UIKit
class ListItem {
var name: String!
var showsImage = false
init(name: String) {
self.name = name
}
}
class MyTableViewController: UITableViewController {
var listItems = [ListItem]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<50 {
let listItem = ListItem(name: "row \(i)")
listItems.append(listItem)
}
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath: indexPath)
cell.textLabel?.text = "\(listItems[indexPath.row].name)"
if listItems[indexPath.row].showsImage {
let myImage = myImage
myImage.tag = 10
cell.addSubview(myImage)
} else {
if let myImage = cell.viewWithTag(10) as? myImage {
myImage.removeFromSuperview()
listItems[indexPath.row].showsImage = false
}
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listItems.count
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
if let myImage = cell.viewWithTag(10) as? myImage {
myImage.removeFromSuperview()
listItems[indexPath.row].showsImage = false
} else {
listItems[indexPath.row].showsImage = true
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}
}
}
EDIT 3: As matt suggested, here's an alternative solution to the code above which subclasses UITableViewCell instead of using a tag for the image.
import UIKit
class MyTableViewCell: UITableViewCell {
var myImage = MyImage()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
myImage.hidden = true
addSubview(myImage)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ListItem {
var name: String!
var showsImage = false
init(name: String) {
self.name = name
}
}
class MyTableViewController: UITableViewController {
var listItems = [ListItem]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<50 {
let listItem = ListItem(name: "row \(i)")
listItems.append(listItem)
}
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = MyTableViewCell(style: .Default, reuseIdentifier: "TestCell")
cell.textLabel?.text = "\(listItems[indexPath.row].name)"
cell.myImage.hidden = !(listItems[indexPath.row].showsImage)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyTableViewCell
listItems[indexPath.row].showsImage = cell.myImage.hidden
cell.myImage.hidden = !cell.myImage.hidden
}
}
The problem is that cells are reused in other rows. When they are, cellForRowAtIndexPath is called again. But when it is, you are supplying no information about the image for that row.
The solution: fix your model (i.e. the info you consult in cellForRowAtIndexPath) so that it knows about the image. In didSelect, do not modify the cell directly. Instead, modify the model and reload the cell.

How to expand and collapse cell correctly like accordion in Swift?

In my app I am trying to play audio files in UITableView. When I tap the cell, it has to expand and play audio. Then if I tap another cell, it should act like accordion, the previous cell must collapse and audio to be stopped. But my implementation doesn't do this:
import UIKit
import AVFoundation
class AudioTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var audioPlayer: AVAudioPlayer?
let mp3sPaths = NSBundle.mainBundle().pathsForResourcesOfType("mp3", inDirectory: nil)
var filteredAudios = [AnyObject]()
var mp3names:NSMutableArray = []
var cellTapped:Bool = true
var currentRow = 0;
override func viewDidLoad() {
super.viewDidLoad()
for mp3 in mp3sPaths as Array<String> {
var mp3name = mp3.lastPathComponent
mp3names.addObject(mp3name.stringByDeletingPathExtension)
}
println(mp3names)
println(mp3sPaths)
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section:Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredAudios.count
} else {
return self.mp3names.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("AudioCell") as AudioCell
if tableView == self.searchDisplayController!.searchResultsTableView {
cell.titleLabel.text = filteredAudios[indexPath.row] as? String
} else {
cell.titleLabel.text = mp3names[indexPath.row] as? String
}
cell.playIcon.text = "▶️"
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var mp3file = mp3sPaths[indexPath.row] as NSString
var mp3URL: NSURL = NSURL.fileURLWithPath(mp3file)!
var error: NSError?
audioPlayer?.stop()
audioPlayer = AVAudioPlayer(contentsOfURL: mp3URL, error: &error)
audioPlayer?.play()
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? AudioCell {
cell.playIcon.text = "◾️"
}
var selectedRowIndex = indexPath
currentRow = selectedRowIndex.row
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? AudioCell {
cell.playIcon.text = "▶️"
}
audioPlayer?.stop()
var selectedRowIndex = indexPath
currentRow = selectedRowIndex.row
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == currentRow {
if cellTapped == false {
cellTapped = true
return 70
} else {
cellTapped = false
return 40
}
}
return 40
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
cell.layer.transform = CATransform3DMakeScale(0.1,0.1,1)
UIView.animateWithDuration(0.25, animations: {
cell.layer.transform = CATransform3DMakeScale(1,1,1)
})
}
func filterContentForSearchText(searchText: String) {
filteredAudios = mp3names as Array
filteredAudios.filter{($0 as NSString).localizedCaseInsensitiveContainsString("\(searchText)")}
}
func searchDisplayController(controller: UISearchDisplayController!, shouldReloadTableForSearchString searchString: String!) -> Bool {
self.filterContentForSearchText(searchString)
return true
}
func tableView(tableView: UITableView!, editActionsForRowAtIndexPath indexPath: NSIndexPath!) -> [AnyObject]! {
var shareAction = UITableViewRowAction(style: .Normal, title: "Share") { (action, indexPath) -> Void in
tableView.editing = false
println("shareAction")
}
shareAction.backgroundColor = UIColor.grayColor()
var doneAction = UITableViewRowAction(style: .Default, title: "Done") { (action, indexPath) -> Void in
tableView.editing = false
println("readAction")
}
doneAction.backgroundColor = UIColor.greenColor()
var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action, indexPath) -> Void in
tableView.editing = false
println("deleteAction")
}
return [deleteAction, doneAction, shareAction]
}
func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
}
}
The screenshots are following:
Can anybody help, please?
I don't think you've shown all the code or the current code in your example.
I have implemented the same kind of thing in swift, and I know the table animations work remarkably well if handled properly.
If the cell frame itself is larger than the height shown by the table and it has content, you need to hide the overhanging subviews in the cell's contentContview when you collapse the cell via heightForRowAtIndexPath, or the visible subview overhanging cell frame will show through the other cells in the table after the cell is collapsed. That may be what's happening in your case but it's hard to tell for sure from your write-up.
But setting the alpha directly all at once looks tacky. You should animate the alpha property of the cell.contentView subviews that need to hide when the cell shrinks, and when the cell expands, using UIView.animateWithDuration() You want them to fade out as the row contracts and fade in as it expands.

Resources