UITableViewCell Item selection - ios

I'm adding UIButton in UITableView, I'm trying to change UIButton background color, UIButton title color and UIButton image color on table view cell selection and same vice versa.
MY Code is
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let propertyCell = tablePropertyList.cellForRowAtIndexPath(indexPath) as! PropertyListTableCell
propertyCell.buttonDownload.selected = true
propertyCell.buttonDownload.setTitleColor(utility!.uicolorFromHex(0xf8f8f8), forState: UIControlState.Selected)
let image:UIImage = UIImage(named: "DownloadSelected")!
propertyCell.buttonDownload.setImage(image, forState: UIControlState.Selected)
propertyCell.buttonDownload.backgroundColor = utility!.uicolorFromHex(0x006747)
propertyCell.buttonDownload.layer.borderColor = utility!.uicolorFromHex(0x006747).CGColor
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
let propertyCell = tablePropertyList.cellForRowAtIndexPath(indexPath) as! PropertyListTableCell
propertyCell.buttonDownload.selected = false
propertyCell.buttonDownload.setTitleColor(utility!.uicolorFromHex(0x006747), forState: UIControlState.Normal)
let image:UIImage = UIImage(named: "Download")!
propertyCell.buttonDownload.setImage(image, forState: UIControlState.Normal)
propertyCell.buttonDownload.backgroundColor = utility!.uicolorFromHex(0xf8f8f8)
propertyCell.buttonDownload.layer.borderColor = utility!.uicolorFromHex(0xf8f8f8).CGColor
}
//on UIButton Action
MY Code is
func downloadViewAction(sender: UIButton)
{
sender.selected = true
sender.setTitleColor(utility!.uicolorFromHex(0xf8f8f8), forState: UIControlState.Selected)
let image:UIImage = UIImage(named: "DownloadSelected")!
sender.setImage(image, forState: UIControlState.Selected)
sender.backgroundColor = utility!.uicolorFromHex(0x006747)
sender.layer.borderColor = utility!.uicolorFromHex(0x006747).CGColor
print("inside ownload action view")
let splitView:UISplitViewController = DevelopmemtSplitViewController()
if let path = tablePropertyList.indexPathForSelectedRow {
let selectedproperty = propertyArray[path.row]
self.showActivityIndicator(splitView.view, message: "Downloading properties for "+selectedproperty)
}
}

awakeFromNib method of cell class can be used to change titlecolor, image of button based on state. Please refer following code
class PropertyListTableCell : UITableViewCell
{
func awakeFromNib()
{
propertyCell.buttonDownload.setTitleColor(utility!.uicolorFromHex(0x006747), forState: UIControlState.Normal)
propertyCell.buttonDownload.setTitleColor(utility!.uicolorFromHex(0xf8f8f8), forState: UIControlState.Selected)
}
}
func downloadViewAction(sender: UIButton)
{
sender.selected = true //automatically changes titlecolor of button
}

If I'm getting it right. You have a button inside every PropertyListTableCell and you want to change the way that button looks depending on the selection state of the cell.
If so, overwrite the setSelected(_:animated:) function in your PropertyListTableCell class, this way, whenever a cell is selected or deselect the button appearance will change automatically.
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: true);
if (selected) {
self.buttonDownload.backgroundColor = utility!.uicolorFromHex(0x006747)
self.buttonDownload.layer.borderColor = utility!.uicolorFromHex(0x006747).CGColor
}
else {
propertyCell.buttonDownload.backgroundColor = utility!.uicolorFromHex(0xf8f8f8)
propertyCell.buttonDownload.layer.borderColor = utility!.uicolorFromHex(0xf8f8f8).CGColor
}
self.buttonDownload.selected = true;
}
As commented Savitha above, the button image and the title color can be defined just once in the awakeFromNib (for example).
And there is no need to change any visual in the button action function because it's done when selecting the cell:
func downloadViewAction(sender: UIButton) {
let cell = sender as! as! PropertyListTableCell;
let indexPath = tableView.indexPathForCell(cell);
tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None);
print("inside ownload action view")
let selectedproperty = propertyArray[path.row]
self.showActivityIndicator(splitView.view, message: "Downloading properties for "+selectedproperty)
}

Related

How to save tableviewcell state?

I am successfully saving the state of tableviewcell by saving the state of cell to dictionary of [IndexPath:Bool] , everything is working fine but problem is when I check mark any cell , a cell from bottom also get strokethrough effect . Only selected cell is supposed to be check marked and strikethrough. Check the image in which bottom is not selected but getting strike through effect , How to resolve this ?
TableViewCell code
let checkedImage = (UIImage(named: "success")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal))! as UIImage
let uncheckedImage = (UIImage(named: "verified")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal))! as UIImage
var isChecked: Bool = false {
didSet{
if isChecked {
tableRadioButton.setImage(checkedImage, for: .normal)
lblItemName.strikeThrough(true)
lblItemQty.strikeThrough(true)
} else {
tableRadioButton.setImage(uncheckedImage, for: .normal)
lblItemName.strikeThrough(false)
lblItemQty.strikeThrough(false)
}
}
}
#IBAction func RadioButtonTapped(_ sender: UIButton) {
isChecked = !isChecked
radioButtonTapAction?(isChecked)
}
Code of cell for row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomOrderDetailCell
cell.setCellData(itemDetail: arrForProducts[indexPath.section].items![indexPath.row],currency: self.currency)
let selected = selectedButtonIndex[indexPath] ?? false
cell.isChecked = selected
cell.radioButtonTapAction = {
(checked) in
selectedButtonIndex[indexPath] = checked
print(checked)
}

Get the indexpath from custom button in accessoryView of a UITableViewCell

I have a UISearchController with a separate UITableViewController as its searchResultsController.
class SearchResultsViewController: UITableViewController {
var fruits: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView(frame: .zero)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
#objc func addFruit(_ sender: UIButton) {
let point = tableView.convert(sender.bounds.origin, to: sender)
let indexPath = tableView.indexPathForRow(at: point)
print(indexPath?.row)
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = fruits[indexPath.row]
cell.selectionStyle = .none
let addButton = UIButton(type: .custom)
addButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
addButton.setImage(UIImage(named: "add"), for: .normal)
addButton.contentMode = .scaleAspectFit
addButton.addTarget(self, action: #selector(addFruit(_:)), for: .touchUpInside)
addButton.sizeToFit()
cell.accessoryView = addButton
return cell
}
}
I need to show a custom button in cells that search results are shown. So I added a UIButton as the cells' accessoryView. And it looks and works fine.
Now I need to get the cell's indexPath when the user taps on this button.
I'm trying to get it like shown below.
#objc func addFruit(_ sender: UIButton) {
let point = tableView.convert(sender.bounds.origin, to: sender)
let indexPath = tableView.indexPathForRow(at: point)
}
But it keeps returning nil for every cell.
Is there any other way to get the indexPath from a custom button tap? I added a demo project here as well.
Create a custom class named SOButton and add variable of type IndexPath to it. Use this class for your add button initialisation.
//Your class will look like -
class SOButton: UIButton {
var indexPath: IndexPath?
}
//Your action will look like -
#objc func addFruit(_ sender: SOButton) {
print(sender?.indexPath.row)
}
//And in your cellForRow add
let addButton = SOButton(type: .custom)
addButton.indexPath = indexPath
Hope this helps you :)
Please update your code. you pass the UIButton sender in convert function , please pass the tableView into them
func getIndexPathByCgPoint(_ sender: UIButton) -> IndexPath? {
let point = sender.convert(sender.bounds.origin, to: tableview)
guard let indexPath = tableview.indexPathForRow(at: point) else {
return nil
}
return indexPath
}
But in case of section header it return nil.
let buttonPosition = sender.convert(CGPoint.zero, to: self.tableView)
let currentIndexPath = self.tableView.indexPathForRow(at: buttonPosition)
Try this it worked for me :)
I would suggest using this light solution: add indexPath.row to button tag:
let addButton = UIButton(type: .custom)
addButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
addButton.tag = indexPath.row
And in button action:
#objc func addFruit(_ sender: UIButton) {
print(sender.tag)
}

how to change button background colour in tableview cell swift3

I have one UITableViewCell. In TableViewCell, I have 7 buttons in single row. I want to play music. When i press button1, its background colour should be changed. If I pressed button2, its background colour should be changed, and button1 would be deselect. I also set the tag for each button in row, but i don't understand, how to do? Sound is playing fine but i am unable to select and deselect buttons. I am using swift3. Thanks in advance.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> tableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerCell") as! tableViewCell
cell.Btn_one.addTarget(self, action: #selector(TableViewController.BtnAction_One), for: .touchUpInside)
//For example
if (cell.Btn_one.tag == 1){
cell.Btn_one.backgroundColor = .white
}else if (cell.Btn_two.tag == 2){
cell.Btn_two.backgroundColor = .red
}
}
#IBAction func BtnAction_One(_ sender: UIButton) {
self.play()
}
#Chetan solution for this : first one
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellData", for: indexPath)
let btn1 = cell.viewWithTag(1) as! UIButton
let btn2 = cell.viewWithTag(2) as! UIButton
let btn3 = cell.viewWithTag(3) as! UIButton
let btn4 = cell.viewWithTag(4) as! UIButton
let btn5 = cell.viewWithTag(5) as! UIButton
let btn6 = cell.viewWithTag(6) as! UIButton
btn1.addTarget(self, action: #selector(btnClicked(sender:)), for: .touchUpInside)
btn2.addTarget(self, action: #selector(btnClicked(sender:)), for: .touchUpInside)
btn3.addTarget(self, action: #selector(btnClicked(sender:)), for: .touchUpInside)
btn4.addTarget(self, action: #selector(btnClicked(sender:)), for: .touchUpInside)
btn5.addTarget(self, action: #selector(btnClicked(sender:)), for: .touchUpInside)
btn6.addTarget(self, action: #selector(btnClicked(sender:)), for: .touchUpInside)
return cell
}
when this will to btnClicked
` func btnClickec(sender:UIButton){
sender.isSelected = true
let cell = sender.superview?.superview as! UITableViewCell
let btn1 = cell.viewWithTag(1) as! UIButton
let btn2 = cell.viewWithTag(2) as! UIButton
let btn3 = cell.viewWithTag(3) as! UIButton
let btn4 = cell.viewWithTag(4) as! UIButton
let btn5 = cell.viewWithTag(5) as! UIButton
let btn6 = cell.viewWithTag(6) as! UIButton
let arr = [btn1,btn2,btn3,btn4,btn5,btn6];
for index in 0...5{
let btn = arr[index]
if index+1 == sender.tag{
btn.isSelected = true
}else{
btn.isSelected = false
}
}
}
`
And second one : or you can collection view inside tableviewcell also
This is how I did it:
first the function:
func switchColor(isWhite: Bool, sender: UIButton) {
if isWhite == true {
sender.backgroundColor = UIColor.clear
sender.setTitleColor(UIColor.white, for: UIControlState.normal)
}else if isWhite == false {
sender.backgroundColor = UIColor.white
sender.setTitleColor(UIColor.clear, for: UIControlState.normal)
}
Then where I call it:
#IBAction func RepeatWeeklyPressed(_ sender: UIButton) {
if sender.backgroundColor == UIColor.white {
switchColor(isWhite: true, sender: sender)
}else {
switchColor(isWhite: false, sender: sender)
}
print("Pressed a repeat button")
}
Hope this helps!
Well, I suggest you to subclass from UIButton, like this:
class CustomButton: UIButton {
var isPressed = false
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect, title: String, tag: Int) {
self.init(frame: frame)
self.frame = frame
setTitle(title, for: .normal)
setTitleColor(.white, for: .normal)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
switch tag {
case 0: //Play a music
if isPressed{
backgroundColor = .black
} else {
backgroundColor = .clear
}
case 1: //Play a video
if isPressed{
backgroundColor = .black
} else {
backgroundColor = .clear
}
default: //Other
if isPressed{
backgroundColor = .black
} else {
backgroundColor = .clear
}
}
if isPressed { isPressed = false } else { isPressed = true }
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
After that, in your cell I'd have some like...
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: nil)
let musicB = CustomButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0), title: "1", tag: 1)
addSubview(musicB)
}
You'll want to subclass the button as CustomButton or whatever you would like to call it. And you'll need to create a delegate to let your viewcontroller know whats up.
Create a func that takes in an integer. This will be the code that'll take in your button's tag and preform some code. #Gabs had the right idea there.
func select(index: Int) {
switch sender.tag {
case 0: //do something
case 1: //do something
}
}
Create a single IBAction then link all your buttons to it. Inside, call the method created above
#IBAction func buttonTapped(_ sender: Any) {
select(index: sender.tag)
}
all that's missing is the viewController being informed on which button has been tapped. Set a delegate for it in your CustomCell view file and have it capture the sender.tag in your IBAction. Be sure to conform your viewcontroller too so the delegation works.

change button image when play completes swift

sender button changes when i click play button but when i click another button in the tableview the button first button image not changes to play
#IBAction func playSound(sender: UIButton) {
if self.player != nil && self.player.playing {
player.stop()
sender.setImage(UIImage(named: "play.png"), forState: UIControlState.Normal)
}
else {
sender.setImage(UIImage(named: "pause.png"), forState: UIControlState.Normal)
}
}
**Try this code ...**
Declare one variable for get index.
var songnamearray : NSArray = NSArray()
var audioPlayer = AVAudioPlayer()
var selectedindex : Int?
var isFristtime : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
songnamearray = ["Saiyaan (Sanam) 320Kbps(MajMasti.in)" ,"Phone Mein Teri Photo (Neha Kakkar) - 320 Kbps(GoldMusic.In)" ,"Mile Ho Tum Humko (Neha Kakkar) - 320 Kbps(GoldMusic.In)" ," Rain Mashup (Neha Kakkar) - 320 Kbps(GoldMusic.In)" ,"Car Mein Music Baja (Neha Kakkar) 320Kbps"]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return songnamearray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Songcell", forIndexPath: indexPath)
// info 5 play 6 name 7
let eventname: UILabel = (cell.viewWithTag(7) as! UILabel)
let info: UIButton = (cell.viewWithTag(5) as! UIButton)
let play: UIButton = (cell.viewWithTag(6) as! UIButton)
if selectedindex == indexPath.row{
if isFristtime == true
{
play.setImage(UIImage(named: "pause-button.png"), forState: UIControlState.Normal)
}else{
play.setImage(UIImage(named: "play-button.png"), forState: UIControlState.Normal)
}
}else{
play.setImage(UIImage(named: "play-button.png"), forState: UIControlState.Normal)
}
info.setImage(UIImage(named: "icon (5).png"), forState: UIControlState.Normal)
play.addTarget(self, action: #selector(self.CloseMethod(_:event:)), forControlEvents: .TouchDown)
info.addTarget(self, action: #selector(self.CloseMethod1(_:event:)), forControlEvents: .TouchDown)
eventname.text = songnamearray.objectAtIndex(indexPath.row) as? String
return cell
}
#IBAction func CloseMethod(sender: UIButton, event: AnyObject) {
let touches = event.allTouches()!
let touch = touches.first!
let currentTouchPosition = touch.locationInView(self.Songlisttable)
let indexPath = self.Songlisttable.indexPathForRowAtPoint(currentTouchPosition)!
selectedindex = indexPath.row
if isFristtime == true
{
audioPlayer.pause()
isFristtime = false
}else{
let songnamestring : NSString = songnamearray.objectAtIndex(indexPath.row) as! String
do {
if let bundle = NSBundle.mainBundle().pathForResource(songnamestring as String, ofType: "mp3") {
let alertSound = NSURL(fileURLWithPath: bundle)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
try audioPlayer = AVAudioPlayer(contentsOfURL: alertSound)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
} catch {
print(error)
}
isFristtime = true
}
self.Songlisttable.reloadData()
}
Try to set background image for button
let image = UIImage(named: "play.png") as UIImage
sender.setBackgroundImage(image, forState: UIControlState.Normal)
Hope this helps.
It is that call radio button. I never use radio button in cell. It is hard for me. I'm newbie. If U need it, it is that: Radio button logic in UItableViewCells.
But i use other way: didSelectRowAtIndexPath. When u click in cell, button current is show pause image, and other button is show play image. U can reference it
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
currentIndexPath = indexPath;
YourTableViewCell *cell = nil;
if (!previousIndexPath) {
previousIndexPath = currentIndexPath;
}
if (previousIndexPath != currentIndexPath) {
cell = (YourTableViewCell *) [_yourTableView cellForRowAtIndexPath:previousIndexPath];
[cell.radioBtn setBackgroundImage:[UIImage imageNamed:#"play"] forState:UIControlStateNormal];
cell = (YourTableViewCell *) [_yourTableView cellForRowAtIndexPath:currentIndexPath];
[cell.radioBtn setBackgroundImage:[UIImage imageNamed:#"pause"] forState:UIControlStateNormal];
previousIndexPath = currentIndexPath;
}
if (previousIndexPath == currentIndexPath) {
cell = (YourTableViewCell *) [_yourTableView cellForRowAtIndexPath:previousIndexPath];
[cell.radioBtn setBackgroundImage:[UIImage imageNamed:#"pause"] forState:UIControlStateNormal];
}
}

Checkbox of collection view take a action without clicking

I'm really confused about this problem of checkbox on collectionView.
I'm already create a class component for 'checkbox' : UIbutton and after that i used
with 'collectionview' so my problem when i click on some checkbox of item
i found another item has checking after :
if i check checkbox of item 1 the other item 6 has checking.
class CheckBox: UIButton {
// Images
let checkedImage = UIImage(named: "checkbox")! as UIImage
let uncheckedImage = UIImage(named: "uncheckbox")! as UIImage
// Bool property
var isChecked: Bool = false {
didSet{
if isChecked == true {
self.setImage(checkedImage, forState: .Normal)
} else if isChecked == false {
self.setImage(uncheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
func buttonClicked(sender: UIButton) {
if sender == self {
println(self)
if isChecked == true {
isChecked = false
} else if isChecked == false {
isChecked = true
}
}
}
}
extension TrackersController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.vehicles.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier,forIndexPath:indexPath) as! VehicleCell
let vehicles: [Vehicle] = dataSource.vehiclesInGroup(indexPath.section)
let vehicle = vehicles[indexPath.row]
cell.txt_mat.text = vehicle.name
cell.txt_imei.text = vehicle.imei
cell.check_veh.addTarget(self, action: "selectVeh:", forControlEvents: UIControlEvents.TouchUpInside)
cell.check_veh.tag = vehicle.id_tracker!.toInt()!
cell.check_veh.enabled = vehicle.subscription!
return cell
}
func selectVeh(button: CheckBox) {
if(button.isChecked){
vehIds.append(button.tag)
}else if(!button.isChecked){
var index = find(vehIds, button.tag)
vehIds.removeAtIndex(index!)
// JLToast.makeText(String(button.tag)).show()
}
}
Image of item 1
Image of item 6
You should store the selected indices in an array and later in cellForRowAtIndexPath method you need to check if indexPath is already there in array or not to show/hide the checkbox.
The appearance of the checkbox is due to the reusing of the cell. The cell's content is loaded every time when cell reappears on screen. So you need to update the content accordingly in cellForRowAtIndex method.
You need take one bool variable in Vehicle modal class (Ex:isSelected) and set value for that bool variable like below in selectVeh method
func selectVeh(button: UIButton) {
button.selected = !button.selected
let vehicle:Vehicle = vehicles[button.tag]
vehicle.isSelected = button.selected;
vehicles.replaceObjectAtIndex(button.tag, withObject: vehicle)
}
in cellForItemAtIndexPath add below code
cell.check_veh.selected = vehicle.isSelected

Resources