I have a table layout inside a view which as a custom cell,The problem I'm facing is that the cells inside has a button i want to hide the button in cell on clicking it(only the one that is clicked should be hidden) how can i do thing in correct method?
ScrollCell.swift
class ScrollCell: UITableViewCell {
#IBOutlet weak var ProfilePic: SpringImageView!
#IBOutlet weak var UserName: SpringButton!
#IBOutlet weak var Closet: UILabel!
#IBOutlet weak var Style: UILabel!
//------//
#IBOutlet weak var MianImg: UIImageView!
//-------//
#IBOutlet weak var ProductName: UILabel!
#IBOutlet weak var LoveCount: UIButton!
#IBOutlet weak var Discount: UILabel!
#IBOutlet weak var OrginalPrice: UILabel!
#IBOutlet weak var Unliked: UIButton!
#IBOutlet weak var Liked: UIButton!
#IBOutlet weak var Comment: UIButton!
#IBOutlet weak var Share: SpringButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func layoutSubviews() {
ProfilePic.layer.cornerRadius = ProfilePic.bounds.height / 2
ProfilePic.clipsToBounds = true
}
}
ScrollController.swift
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1 // however many sections you need
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(try! Realm().objects(Feed))
var FeedModel = Feed()
let realm = try! Realm()
let tan = try! Realm().objects(Feed).sorted("ID", ascending: false)
return tan.count // however many rows you need
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// get an instance of your cell
cell = tableView.dequeueReusableCellWithIdentifier("ScrollCellDqueue", forIndexPath: indexPath) as! ScrollCell
IndexPath = indexPath.row
var FeedModel = Feed()
let realm = try! Realm()
let tan = try! Realm().objects(Feed).sorted("ID", ascending: false)
cell.ProfilePic.kf_setImageWithURL(NSURL(string:tan[indexPath.row].ProfilePic)!)
cell.UserName.setTitle(tan[indexPath.row].FullName, forState: .Normal)
cell.Style.text = tan[indexPath.row].StyleType
if tan[indexPath.row].UserType == "store_front"{
cell.Closet.text = "Store Front"
}else if tan[indexPath.row].UserType == "normal"{
cell.Closet.text = "Pri Loved"
}
//-----//
var SingleImage:String = ""
var ImageArray = tan[indexPath.row].ImageArraySet.componentsSeparatedByString(",")
SingleImage = ImageArray[0]
cell.MianImg.kf_setImageWithURL(NSURL(string:SingleImage)!)
//-----//
cell.ProductName.text = tan[indexPath.row].ItemName
cell.OrginalPrice?.text = "\(tan[indexPath.row].OrginalPrice)"
cell.LoveCount.setTitle("\(tan[indexPath.row].LikeCount)"+" Loves", forState: .Normal)
cell.Discount.text = "\(tan[indexPath.row].Discount)"+" % off"
if(tan[indexPath.row].LikeStatus){
cell.Unliked.hidden = true
cell.Liked.hidden = false
}
else if (!tan[indexPath.row].LikeStatus){
cell.Unliked.hidden = false
cell.Liked.hidden = true
}
cell.Unliked.tag = tan[indexPath.row].ID
cell.Liked.tag = tan[indexPath.row].ID
return cell
}
#IBAction func LikeBtn(sender: AnyObject) {
print(sender.tag)
print(IndexPath)
//here i want to know who i can hide the button i have clicked ?
}
Here i want to access the cell in which button is clicked and make changes to UI item inside that cell how can i do that ?
There are many ways to do it. One possible solution is use block.
Add this to ScrollCell
var didLikedTapped: (() -> Void)?
and receive the event of the LikedButton in the cell
#IBAction func LikeBtn(sender: AnyObject) {
didLikedTapped?()
}
Then in cellForRowAtIndexPath of viewController add this
cell.didLikedTapped = {[weak self] in
print(IndexPath)
}
Liked is uibutton in ScrollCell, i don't known, why can you add IBAction for it in ScrollController? . You must implement it in ScrollCell And code:
#IBAction func LikeBtn(sender: UIButton) {
print(sender.tag)
sender.hiden = true
}
And i think, if you have only one UIbutton, it will better. In there, like and unlike is 2 state of uibutton(seleted and none). When you click the button, change it's state
Update:
class sampleCell: UITableViewCell{
#IBOutlet var btnLike : UIButton!
#IBOutlet var btnUnLike : UIButton! // frame of 2 button is equal
override func awakeFromNib() {
super.awakeFromNib()
self.btnUnLike.hidden = true
// ...
}
func updateData(data:AnyObject){ // data's type is Feed
// set data for cell
// i think you should implement in here. and in ScollController call : cell.updateData() , it's better
/* e.x
self.ProductName.text = tan[indexPath.row].ItemName
self.OrginalPrice?.text = "\(tan[indexPath.row].OrginalPrice)"
self.LoveCount.setTitle("\(tan[indexPath.row].LikeCount)"+" Loves", forState: .Normal)
self.Discount.text = "\(tan[indexPath.row].Discount)"+" % off"
*/
}
#IBAction func likeTap(sender:UIButton){ // rememeber set outlet event for btnLike and btnUnLike is this function
if sender == self.btnLike{
self.btnLike.hidden = true
self.btnUnLike.hidden = false
// do s.t
}else if sender == self.btnUnLike{
self.btnLike.hidden = false
self.btnUnLike.hidden = true
// do s.t
}
}
}
Check if the following code help
#IBAction func LikeBtn(sender: AnyObject) {
var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(position)
let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as
UITableViewCell
print(indexPath?.row)
}
give the LikeBtn the property indexpath, in cellForRowAtIndexPath method, pass the indexPath to the LikeBtn, then you will know which cell's LikeBtn clicked.
class LikeBtn: UIButton {
var indexPath: NSIndexPath?
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
// here pass the indexpath to your button
cell.likeBtn.indexPath = indexPath
return cell
}
#IBAction func likeTap(sender: LikeBtn){
if let indexPath = sender.indexPath {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
//here you will know the exact cell, now you can hide or show your buttons
}
}
}
Related
I am trying to display table view cell property into different table view cell when button I clicked . I am using story board . I added the Horizontal and vertical stack to contains the image and label properties . I want to display this property into another table view cell when user clicked the show button . In cellFor row function i defined the button action property . I am getting following error .Class 'DetailsViewCell' has no initializers. Cannot use instance member 'mc' within property initializer; property initializers run before 'self' is available
Here is the screenshot of the both view controller .
Here is the code .
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// guard let cell = tableView.dequeueReusableCell(withIdentifier: MovieCell.identifier, for: indexPath) as? MovieCell
// else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
cell.showButton.tag = indexPath.row
cell.showButton.addTarget(self, action: Selector("movieDetails"), for: .touchUpInside)
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
}
Here is the code in identifier class with table view cell.
class MovieViewCell: UITableViewCell {
static let identifier = "MovieViewCell"
#IBOutlet weak var mainStackView: UIStackView!
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTtile: UILabel!
#IBOutlet weak var movieOverview: UILabel!
#IBOutlet weak var showButton: UIButton!
#IBAction func movieDetails(_ sender: UIButton) {
var dc : DetailsViewCell
movieTtile = dc.movieTitle
movieOverview = dc.movieOverview
movieImage = dc.movieImage
}
func configureCell(title: String?, overview: String?, data: Data?) {
movieTtile.text = title
movieOverview.text = overview
if let imageData = data{
movieImage.image = UIImage(data: imageData)
}
}
}
Here is the code for Details view cell.
class DetailsViewCell: UITableViewCell {
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
#IBOutlet weak var movieImage: UIImageView!
var mc : MovieViewCell
movieTitle = mc.movieTtile
movieOverview = mc.movieOverview
movieImage = mc.movieImage
}
import UIKit
var loginData = ["", "", ""]
class LoginDataCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var txtLoginData: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField.tag == 0 {
loginData[0] = textField.text
} else if textField.tag == 1 {
loginData[1] = textField.text
} else if textField.tag == 2 {
loginData[2] = textField.text
}
}
}
I want to make a selected cell a specific color (UIColor.systemGray). I've tried almost every answer out there but for some reason the way that my cells are it isn't working.
Here is part of my view controller class:
extension CommunicationViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return communicationcells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let communicationCell = communicationcells[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "CommunicationCell") as! CommunicationCell
cell.backgroundButton.tag = indexPath.row
cell.backgroundButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
cell.setCommunication(communication: communicationCell)
return cell
}
struct Holder {
static var _myComputedProperty:Int = -1
}
var myComputedProperty:Int {
get {
return Holder._myComputedProperty
}
set(newValue) {
Holder._myComputedProperty = newValue
}
}
#objc func buttonTapped(_ sender: UIButton) {
myComputedProperty = sender.tag
performSegue(withIdentifier: "CommunicationSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailsController = segue.destination as! CommunicationDetailsViewController
detailsController.passthroughstring = String(myComputedProperty)
}
}
And here is my communication cell controller:
class CommunicationCell: UITableViewCell {
#IBOutlet var backgroundcontentView: UIView!
#IBOutlet weak var CommunicationType: UILabel!
#IBOutlet weak var subject: UILabel!
#IBOutlet weak var partnerType: UILabel!
#IBOutlet weak var partnerID: UILabel!
#IBOutlet weak var effectiveFrom: UILabel!
#IBOutlet weak var effectiveTo: UILabel!
#IBOutlet weak var downtimeFrom: UILabel!
#IBOutlet weak var downtimeTo: UILabel!
#IBOutlet weak var backgroundButton: UIButton!
#IBOutlet var collectionOfCommunicationLabels: Array<UILabel>!
func applyTheme() {
for i in 0..<collectionOfCommunicationLabels.count {
collectionOfCommunicationLabels[i].textColor = Theme.current.textColor
collectionOfCommunicationLabels[i].backgroundColor = Theme.current.backgroundColor
}
backgroundcontentView.backgroundColor = Theme.current.backgroundColor
CommunicationType.textColor = Theme.current.textColor
subject.textColor = Theme.current.textColor
partnerType.textColor = Theme.current.textColor
partnerID.textColor = Theme.current.textColor
effectiveFrom.textColor = Theme.current.textColor
effectiveTo.textColor = Theme.current.textColor
downtimeFrom.textColor = Theme.current.textColor
downtimeTo.textColor = Theme.current.textColor
// backgroundButton.backgroundColor = Theme.current.backgroundColor
}
func setCommunication(communication: Communication) {
CommunicationType.text = communication.communicationType
subject.text = communication.subject
partnerType.text = communication.partnerType
partnerID.text = communication.partnerID
effectiveFrom.text = communication.effectiveFrom
effectiveTo.text = communication.effectiveTo
downtimeFrom.text = communication.downtimeFrom
downtimeTo.text = communication.downtimeTo
applyTheme()
}
}
I've tried almost every answer on stack overflow and nothing has worked for me.
Can you please try to implement the didSelectRowAtIndexPath method in addition to the cellForRowAtIndexPath method? In that case, you will not need a background button and also you will get a callback in the didSelectRowAtIndexPath method on tapping any row in the tableview.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
selectCell.backgroundColor = .red //change to any color you want it to change to on selection
performSegue(withIdentifier: "CommunicationSegue", sender: self)
}
I'm trying to get the selected row in a table in Swift 4. The code presented for completeness, is as follows:
import UIKit
import WebKit
class FactorDetailsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var goalTitle: UILabel!
#IBOutlet weak var goalCopy: UITextView!
#IBOutlet weak var goalBenefit: UILabel!
#IBOutlet weak var goalName: UILabel!
#IBOutlet weak var graph: SimpleChart!
#IBOutlet weak var measurement: UILabel!
#IBOutlet weak var measurementRange: UILabel!
#IBOutlet weak var updated: UILabel!
#IBOutlet weak var factorCopy: UITextView!
#IBOutlet weak var impact: UILabel!
#IBOutlet weak var actionsTable: UITableView!
#IBOutlet weak var researchTable: UITableView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var stackView: UIStackView!
var factorData : Factor?
var currentCategory : FactorCategory?
var recommendedActions : [Action] = []
var relatedResearch : [Research] = []
var goal : Goal?
var reading:Double?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.title = factorData?.factorName
measurement.text = String(reading!)
self.actionsTable.delegate = self
self.actionsTable.dataSource = self
self.actionsTable.isEditing = false
self.researchTable.delegate = self
self.researchTable.dataSource = self
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Update", style: .done, target: self, action: #selector(addStuff))
goalCopy.text = goal?.copy
goalBenefit.text = "BIG BENEFIT"
goalTitle.text = goal?.title
for cat in (factorData?.categories)! {
let s = SimpleChartData(min : Double(cat.min), max : Double(cat.max), label : cat.label, label2 : String(cat.max))
if( graph.canLoad ) {
graph.data!.append(s)
}
}
graph.reading = reading!
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
}
#objc func addStuff() {
// how does this work? Just takes you to the quiz again
let storyboard = UIStoryboard(name: "12Factor", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "AllQuestionViewController") as UIViewController
present(vc, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func configure( factor : Factor )
{
factorData = factor
let mirrored_object = Mirror(reflecting: HRResponses.shared)
reading = 1.0
for (_, attr) in mirrored_object.children.enumerated() {
if let property_name = attr.label as String? {
if factorData?.responseField == property_name {
if let a = attr.value as? String, let aDouble = Double(a) {
reading = aDouble
}
}
}
}
currentCategory = factor.categories.first( where: {$0.min < reading! && $0.max > reading! })
for aind in (currentCategory?.actions)! {
let act = SignalModel.model.actions.first( where: {$0.id == aind})
recommendedActions.append(act!)
}
for rind in (currentCategory?.research)! {
let act = SignalModel.model.research.first( where: {$0.id == rind})
relatedResearch.append(act!)
}
goal = SignalModel.model.goals.first( where: {$0.id == currentCategory?.goals[0]})
}
func tableView(_ tableView: UITableView,
willSelectRowAt indexPath: IndexPath) -> IndexPath? {
print("works?")
return nil
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if tableView == self.actionsTable {
let vc : ActionViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ActionViewController") as! ActionViewController
navigationController?.pushViewController(vc, animated: true)
}
if tableView == self.researchTable {
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of items in the sample data structure.
var count:Int?
if tableView == self.actionsTable {
count = currentCategory?.actions.count
}
if tableView == self.researchTable {
count = currentCategory?.research.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.actionsTable {
cell = tableView.dequeueReusableCell(withIdentifier: "ActionCell", for: indexPath as IndexPath)
let action = recommendedActions[indexPath.row]
(cell as! ActionCell).configure(a:action)
}
if tableView == self.researchTable {
cell = tableView.dequeueReusableCell(withIdentifier: "ResearchCell", for: indexPath as IndexPath)
let research = relatedResearch[indexPath.row]
(cell as! ResearchCell).configure(r:research)
}
return cell!
}
}
Now, that's too much code. The relevant parts are here:
self.actionsTable.delegate = self // yes, this is the delegate
self.actionsTable.dataSource = self
self.actionsTable.isEditing = false // no, we're not editing
As I understand it, this should be enough to have selections in the actionsTable trigger the
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
method. However, nothing happens. The other UITableViewDelegate methods are called, so this controller is the delegate for this table, however this one method is not ever triggered. Reading through the Apple documentation here I see that the method isn’t called when the table view is in editing mode (that is, the isEditing property of the table view is set to true), but my table isn't in editing mode. Is there something else that could be going wrong with my table that wouldn't allow it to send an event to a UITableViewDelegate? I suspect that this has something to do with the table being inside a UIScrollView, which I've read isn't best practice, but with the design I've been given, is non-negotiable sadly.
Your problem is not the delegate, all of that code is good. Your problem is that the parent scroll view is consuming the taps, not the table view. Remember, UITableView is a direct subclass of UIScrollView so placing a table view inside a scroll view is no different than placing a scroll view within a scroll view. UITableView has all of the default scroll view delegates built into it so just use those.
You should not embed UIWebView or UITableView objects in UIScrollView
objects. If you do so, unexpected behavior can result because touch
events for the two objects can be mixed up and wrongly handled.
Apple dox
I know it's not the answer you wanted because this wasn't your doing but I personally would not proceed with a hack. I would restructure the code and trim the controller down to one scroll view.
I have this custom UITableViewCell:
class CircleOfTrustTableViewCell: UITableViewCell {
#IBOutlet var permissionTitle: UILabel!
#IBOutlet weak var permissionImage: UIImageView!
#IBOutlet weak var permissionSwitch: UISwitch!
#IBOutlet weak var spacingView: UIView!
// Update toggle based on user visibility and category type
func update(showUser: Bool, index: Int){
self.tag = index
let type = ProfileContentTypeActual.all[index]
self.permissionImage.image = UIImage(named: categoryImages[type]!)
self.permissionTitle.text = categoryNames[type]
if showUser {
self.permissionSwitch.tag = index
self.permissionSwitch.isEnabled = true
if let toggles = GlintUser.getThisUser().trust_toggle {
self.permissionSwitch.setOn(toggles.getState(type), animated: true)
}
} else {
self.permissionSwitch.setOn(false, animated: true)
self.permissionSwitch.isEnabled = false
}
}
}
I implement the cell this way:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
settingsTableView.register(UINib(nibName: "COTTableViewCell", bundle: nil), forCellReuseIdentifier: "cotCell")
let cotCell = (settingsTableView.dequeueReusableCell(withIdentifier: "cotCell") as! CircleOfTrustTableViewCell)
cotCell.update(showUser: showUser, index: indexPath.row)
return cotCell
}
My question is: Is it best practice to call the update function on the cell (to populate its data) or is it best to leave this in the cellForRowAtIndexPath method?
I have a button on my custom tableview cell that is showing the users name. When you click on it, you should be taken to his/her profile but nothing happens?
Here is my custom tableview cell class (commentsTableViewCell.swift) :
import UIKit
protocol commentsTableViewCellDelegate {
func namesIsTapped(cell: commentsTableViewCell)
}
class commentsTableViewCell: UITableViewCell {
#IBOutlet weak var nameButton: UIButton!
#IBOutlet weak var commentLabel: UILabel!
#IBOutlet weak var profilePic: UIImageView!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var uidLabel: UILabel!
var delegate: commentsTableViewCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func nameIsTapped(sender: AnyObject) {
//4. call delegate method
//check delegate is not nil
if let _ = delegate {
delegate?.namesIsTapped(self)
} else {
print("Delegate is \(delegate)")
}
}
}
Here is the important part of commentsTableViewController.swift:
class commentsTableViewController: UITableViewController, commentsTableViewCellDelegate, UITextViewDelegate {
#IBOutlet weak var commentLabel: UITextView!
#IBOutlet weak var theLabel: UILabel!
var dataGotten = "Nothing"
var updates = [CommentSweet]()
func namesIsTapped(cell: commentsTableViewCell) {
//Get the indexpath of cell where button was tapped
//let indexPath = self.tableView.indexPathForCell(cell)
let allDataSend = cell.nameButton.titleLabel?.text!
self.performSegueWithIdentifier("toDetailtableViewController", sender: allDataSend)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toDetailtableViewController" {
if let nextVC = segue.destinationViewController as? theProfileTableViewController {
nextVC.viaSegue = sender! as! String
}
}
}
override func viewDidLoad() {
Kindly set the delegate to self.
In cellforRowIndexPath
commentsTableViewCell.delegate = self
Where commentsTableViewCell is the custom UITableViewCell object
I suggest to handle the action of the cell's button in the viewController. You can recognize which button has been tapped by setting a tag for it.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
cell.myButton?.tag = indexPath.row
cell.myButton?.addTarget(self, action: #selector(), for: .touchUpInside)
return cell
}
func namesIsTapped(tappedButton: UIButton) {
// get the user (from users array for example) by using the tag, for example:
let currentUser = users[tappedButton.tag]
// do whatever you want with this user now...
}