I would like that users can choose maximum one voice. And that the checkmark jumps to where you tapt and deselect the other.
It looks like very simple, but I don't see the solution. And I can't find the answer on the internet.
Please can anybody help me?
Thanks advance!
import UIKit
import AVFoundation
class voicesTableViewController: UITableViewController {
fileprivate let synthesizer = AVSpeechSynthesizer()
fileprivate var speechVoices = AVSpeechSynthesisVoice.speechVoices()
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return speechVoices.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
//Name
let voice = speechVoices[indexPath.row]
let voiceLang = voice.language as? String
let theVoice = UserDefaults.standard.object(forKey:"voice") as? String
cell.textLabel?.text = voice.name
// Language
if let language = countryName(countryCode: voice.language) {
cell.detailTextLabel?.text = "\(language)"
}
else {
cell.detailTextLabel?.text = ""
}
cell.detailTextLabel?.textColor = UIColor.gray
// Checkmark
if (theVoice != nil) {
if(theVoice == voiceLang) {
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let voice = speechVoices[indexPath.row]
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
else
{
//if ((tableView.indexPathsForSelectedRows?.count)! > 1) {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
//}
}
UserDefaults.standard.set(voice.language, forKey:"voice")
UserDefaults.standard.synchronize()
tableView.deselectRow(at: indexPath, animated: true)
}
func countryName(countryCode: String) -> String? {
let preferredLanguage = NSLocale.preferredLanguages[0] as String
let current = Locale(identifier: preferredLanguage)
return current.localizedString(forLanguageCode: countryCode) ?? nil
//return current.localizedString(forIdentifier: indentifier) ? nil
}
}
Simple change of function cellForRow:atIndexPathshould work:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
//Name
let voice = speechVoices[indexPath.row]
let voiceLang = voice.language as? String
let theVoice = UserDefaults.standard.object(forKey:"voice") as? String
cell.textLabel?.text = voice.name
// Language
if let language = countryName(countryCode: voice.language) {
cell.detailTextLabel?.text = "\(language)"
}
else {
cell.detailTextLabel?.text = ""
}
cell.detailTextLabel?.textColor = UIColor.gray
// Checkmark
if(theVoice != nil && theVoice == voiceLang) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
UPD#1
But you can use better solution:
1) Add property fileprivate var selectedIndexPath: IndexPath?
2) Change function func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)to next one:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
//Name
let voice = speechVoices[indexPath.row]
let voiceLang = voice.language as? String
let theVoice = UserDefaults.standard.object(forKey:"voice") as? String
cell.textLabel?.text = voice.name
// Language
if let language = countryName(countryCode: voice.language) {
cell.detailTextLabel?.text = "\(language)"
}
else {
cell.detailTextLabel?.text = ""
}
cell.detailTextLabel?.textColor = UIColor.gray
// Checkmark
cell.accessoryType = self.selectedIndexPath == indexPath ? .checkmark : .none
return cell
}
3) And then in func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) you can do next:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let voice = speechVoices[indexPath.row]
self.selectedIndexPath = indexPath
UserDefaults.standard.set(voice.language, forKey:"voice")
UserDefaults.standard.synchronize()
tableView.deselectRow(at: indexPath, animated: true)
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Related
in my swift code below when one tableview cell is deleted the tableview cells after is not showing a change in the place of the number. So when 2 is deleted what is left is 1 and 3 it should just state 1 and 2. I listed my code below with the delete function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let title = itemName[indexPath.row]
let cell = theScores.dequeueReusableCell(withIdentifier: "MyCell", for : indexPath)
cell.selectionStyle = .default
if let position = title.value(forKey: "positon") {
cell.textLabel?.text = "Item : \(title.positon))"
}
cell.textLabel?.text = "Item: \(title.positon)"
cell.textLabel?.textAlignment = .center
cell.layoutMargins = UIEdgeInsets.zero
cell.preservesSuperviewLayoutMargins = false
cell.separatorInset = UIEdgeInsets.zero
cell.layoutMargins = UIEdgeInsets.zero
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemName.count
}
var itemName : [Player] = []
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
let appd = UIApplication.shared.delegate as! AppDelegate
let context = appd.persistentContainer.viewContext
context.delete(itemName[indexPath.row])
itemName.remove(at: indexPath.row)
do {
try context.save()
}
catch {
print("d")
}
self.theScores.reloadData()
}
}
I try to hide or start the indexPath.row at 1. how can i achieved that ?. I already reversed the indexPath and make the count on numberOfRowsInSection - 1, So the list start from the buttom, but when i clicked on the list the content still not changed according to the reversed indexPath.row
Here is my code
extension PaymentMethodViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return paymentMethod.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = paymentMethod[indexPath.row]
switch indexPath {
case indexPathForSelected:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ConstantsIdentifier.paymentMethodCellId,
for: indexPath) as? PaymentMethodCell else {
return UITableViewCell()
}
cell.layoutIfNeeded()
cell.setNeedsLayout()
cell.paymentLbl.text = data.paymentGroupTitle
cell.subLbl.text = selectedPayment.title
cell.descriptionLabel.text = selectedPayment.description
cell.phoneNumberTextField.addTarget(self, action: #selector(textFieldDidChange(sender:)), for: .editingChanged)
cell.phoneNumberTextField.isHidden = selectedPayment.title == ConstantsText.titleOVO ? false : true
cell.phoneNumberTextField.textContentType = .telephoneNumber
cell.phoneNumberTextField.keyboardType = .phonePad
cell.phoneNumberTextField.delegate = self
selectedPayment.code == ConstantsPaymentMethod.defaultPaymentCode ? cell.withSeparator() : cell.removeSeparator()
cell.rightIcon.image = selectedPayment.code == ConstantsPaymentMethod.defaultPaymentCode ? UIImage(named: ConstantsImage.ovalTick) : UIImage(named: ConstantsImage.arrowRight)
cell.rightIcon.contentMode = .scaleAspectFit
if selectedPayment.code == ConstantsPaymentMethod.defaultPaymentCode {
hideCellDesc(cell, true)
} else {
hideCellDesc(cell, false)
}
let imageUrl = URL(string: selectedPayment.logo?.lowres ?? "")
if let objectPayment = paramCheckout?["payment"] as? NSDictionary, let ccNumber = objectPayment["cardNumber"] as? String, !ccNumber.isEmpty {
cell.paymentImg.image = UIImage(named: getImageCC(ccName: getTypeCreditCard(ccNumber: ccInfo?.ccNumber ?? "")))
} else {
cell.paymentImg?.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ConstantsImage.placeholder), options: .highPriority, completed: nil)
}
return cell
default:
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: ConstantsIdentifier.defaultIndentifier, for: indexPath)
cell.textLabel?.text = data.paymentGroupTitle
cell.textLabel?.numberOfLines = 2
cell.textLabel?.font = UIFont.karlaRegular
let image = UIImageView(image: UIImage(named: ConstantsImage.arrowRight))
cell.accessoryView = image
cell.selectionStyle = .none
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPathForSelected == indexPath && selectedPayment.title == ConstantsText.titleOVO {
return Constant.SelectedHeight + 30
}
if indexPathForSelected == indexPath && selectedPayment.code == ConstantsPaymentMethod.creditCard {
return Constant.CellHeight
}
return indexPathForSelected == indexPath ? Constant.SelectedHeight + 30 : Constant.CellHeight
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return Constant.HeaderHeight
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return ConstantsText.titlePaymentMethod
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
view.tintColor = UIColor.white
let header = view as! UITableViewHeaderFooterView
header.textLabel?.font = UIFont.karlaBold
header.textLabel?.textColor = UIColor.mainBlue
}
}
Please help me, Thanks
Firstly add UITableViewDelegate, I think this is the problem:
extension PaymentMethodViewController: UITableViewDataSource, UITableViewDelegate {}
and
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
I am working on a location-based reminder app. I show all reminders that user created on a table view. I have also UISwitch on every cell. I want that UISwitch disables/enables reminders individually, not all notifications. I couldn't figure it out.
extension MainViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! itemTableViewCell
let item = self.items![indexPath.row]
cell.itemTitle?.text = item.itemName
cell.itemSubTitle?.text = item.itemDescription
//switch
let swicthView = UISwitch(frame: .zero)
swicthView.onTintColor = UIColor (named: "DingerBlue")
swicthView.setOn(true, animated: true)
swicthView.tag = indexPath.row
swicthView.addTarget(self, action: #selector(self.SwitchBtn(_:)), for: .valueChanged)
cell.accessoryView = swicthView
let itemToRemove = self.items![indexPath.row]
let notifToRemove: String = itemToRemove.notifID!
return cell
}
#objc func switchDidChanged(_ sender: UISwitch){
print("Switch value is \(sender.isOn)")
if(sender.isOn){
print("on")
UIApplication.shared.registerForRemoteNotifications()
}
else{
print("Off")
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notifToRemove])
}
}
}
I believe your code is not working because cells are reused and actions on specific cells should be handled from the cell class rather than from ViewController. Move this code into the UITableViewCell code.
let swicthView = UISwitch(frame: .zero)
swicthView.onTintColor = UIColor (named: "DingerBlue")
swicthView.setOn(true, animated: true)
swicthView.tag = switchViewTag!
swicthView.addTarget(self, action: #selector(self.SwitchBtn(_:)), for: .valueChanged)
#objc func switchDidChanged(_ sender: UISwitch){
print("Switch value is \(sender.isOn)")
if(sender.isOn){
print("on")
UIApplication.shared.registerForRemoteNotifications()
}
else{
print("Off")
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notifToRemove])
}
}
and add a new property in the UITableViewCell
weak var switchViewTag: Int?
Modify your cellForRowAt delegate method to
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! itemTableViewCell
let item = self.items![indexPath.row]
cell.itemTitle?.text = item.itemName
cell.itemSubTitle?.text = item.itemDescription
cell.switchViewTag = indexPath.row
return cell
}
Cell with enabled checkmark before scrolling:
Cells with disabled checkmarks after I have scrolled up:
hey Guys, I have created a tableview and an add button to add new cells. when i add cells and i enable the UITableViewCell.AccessoryType.checkmark the checkmarks disappear when i scroll the tableview and the cells disappear out of the view.
how can i fix it ?
var waterValue = [String]()
#IBAction func addButtonPressed(_ sender: Any) {
let alert = UIAlertController(title: "add your amount of water for today", message: nil, preferredStyle: .alert)
alert.addTextField(configurationHandler: {(waterAmountTodayTF) in waterAmountTodayTF.placeholder = "enter L for today"})
alert.textFields?.first?.textAlignment = .center
alert.textFields?.first?.becomeFirstResponder()
alert.textFields?.first?.keyboardType = UIKeyboardType.decimalPad
let action = UIAlertAction(title: "add", style: .default) {
(_) in
guard let waterAmountForToday = (alert.textFields?.first?.text) else { return }
self.add("\(waterAmountForToday) L")
// print(self.sliderValue)
}
alert.addAction(action)
present(alert, animated: true)
}
func add(_ individualWaterAmount: String) {
let index = 0
waterValue.insert(individualWaterAmount, at: index)
let indexPath = IndexPath(row: index, section: 0)
tableView.insertRows(at: [indexPath], with: .left)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return waterValue.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let individualWaterValues = waterValue[indexPath.row]
cell.textLabel?.text = individualWaterValues
cell.textLabel?.textAlignment = .right
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCell.AccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.none
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
guard editingStyle == .delete else { return }
waterValue.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
You have not added logic to set accessory type to checkmark while creating new cell.
What you need to do is, save the value which you have selected, and then use that values while creating new cell.
var selectedIndexes: [Int] = []; //global variable
...
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let individualWaterValues = waterValue[indexPath.row]
cell.textLabel?.text = individualWaterValues
cell.textLabel?.textAlignment = .right
cell.accessoryType = selectedIndexes.contains(indexPath.row) ? UITableViewCell.AccessoryType.checkmark : UITableViewCell.AccessoryType.none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCell.AccessoryType.checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.none
selectedIndexes.removeAll(where: { $0 == indexPath.row } )
} else {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark
selectedIndexes.append(indexPath.row)
}
}
I have a problem handling 2 tables on the same screen. Every time he keeps crashing. Can someone help me?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: TableViewCellComunicazioni?
if tableView == self.tableViewNotifica {
cell = tableView.dequeueReusableCell(withIdentifier: "cellNotifica", for: indexPath) as? TableViewCellComunicazioni
let dataNotifica = structNotifica[indexPath.row].dateNotifica
let testoNotifica = structNotifica[indexPath.row].textNotifica
cell?.dateNotification.text = "\(date!)"
cell?.textNotification.text = "\(text!)"
return cell!
}
if tableView == self.tableViewInbox {
cell = tableView.dequeueReusableCell(withIdentifier: "cellInbox", for: indexPath) as? TableViewCellComunicazioni
let email = structInbox[indexPath.row].email
let messaggio = structInbox[indexPath.row].messaggio
let data = structInbox[indexPath.row].data
cell?.emailInbox.text = "\(email!)"
cell?.messaggioInbox.text = "\(message!)"
cell?.dataInbox.text = "\(date!)"
return cell!
}
return UITableViewCell()
}
This could be a probable fix for your problem:
Coding Example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == self.tableViewNotifica {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellNotifica", for: indexPath) as? TableViewCellComunicazioni
let dataNotifica = structNotifica[indexPath.row].dateNotifica
let testoNotifica = structNotifica[indexPath.row].textNotifica
cell?.dateNotification.text = "\(date!)"
cell?.textNotification.text = "\(text!)"
return cell!
}
if tableView == self.tableViewInbox {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellInbox", for: indexPath) as? TableViewCellComunicazioni
let email = structInbox[indexPath.row].email
let messaggio = structInbox[indexPath.row].messaggio
let data = structInbox[indexPath.row].data
cell?.emailInbox.text = "\(email!)"
cell?.messaggioInbox.text = "\(message!)"
cell?.dataInbox.text = "\(date!)"
return cell!
}
return UITableViewCell()
}
And make sure that you have correct cell identifier for dequeuing.
extension ViewController : UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listmoviesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == moviesTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieTableViewCell", for: indexPath) as! MovieTableViewCell
cell.delegate = self
cell.setupCell(listmoviesArray[indexPath.row],indexPath: indexPath)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieTableViewCell2", for: indexPath) as! MovieTableViewCell
cell.delegate = self
cell.setupCell(listmoviesArray[indexPath.row],indexPath: indexPath)
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == moviesTableView {
// Handle your selection for row.
} else {
//Handle your selection for row.
}
}
}
Above code produces the following output with 2 Tableview.