Swift: изменение изображения кнопки в виде таблицы при нажатии

Я создал проект Xcode для iPhone, используя Swift, с Parse в качестве серверной части. Моя текущая проблема связана с созданием приложения списка дел как одной вкладки более крупного приложения.

Внутри пользовательской ячейки-прототипа я хочу иметь кнопку-флажок, которая меняет свое изображение при нажатии, а также изменение переменной isChecked:Bool для этой ячейки. Я прошел большую часть пути, но столкнулся с кирпичной стеной в отношении настройки и доступа к соответствующим переменным для этой кнопки.

Редактировать: благодаря приведенному ниже ответу и другим ресурсам я наконец-то написал рабочий код для этой функциональности флажка. По сути, свойство тега кнопки устанавливается равным indexPath.row объекта PFObject. Поскольку мой первоначальный вопрос был немного широким, я обновляю свой код ниже, чтобы он мог помочь другим новым разработчикам, которые работают над аналогичной функциональностью. Возможно, есть лучшие способы, но этот вроде работает.

// ЗадачиVC.swift

var taskObjects:NSMutableArray! = NSMutableArray()

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)    
    self.fetchAllObjects()
}

func fetchAllObjects() {

    var query:PFQuery = PFQuery(className: "Task")

    query.whereKey("username", equalTo: PFUser.currentUser()!)

    query.orderByAscending("dueDate")
    query.addAscendingOrder("desc")

    //fetches values within pointer object
    query.includeKey("deal")

    query.findObjectsInBackgroundWithBlock { (tasks: [AnyObject]!, error:NSError!) -> Void in

        if (error == nil) {

            var temp:NSArray = tasks! as NSArray
            self.taskObjects = temp.mutableCopy() as NSMutableArray

            self.tableView.reloadData()

            println("Fetched objects from server")

        } else {
            println(error?.userInfo)
        }
    }
}


//MARK: - Tasks table view
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.taskObjects.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as TaskCell

    var dateFormatter:NSDateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "M/dd/yy"

    var task:PFObject = self.taskObjects.objectAtIndex(indexPath.row) as PFObject

    cell.desc_Lbl?.text = task["desc"] as? String
    cell.date_Lbl.text = dateFormatter.stringFromDate(task["dueDate"] as NSDate)

    //value of client within Deal pointer object
    if let deal = task["deal"] as? PFObject {
        // deal column has data
        if let client = deal["client"] as? String {
            // client has data
            cell.client_Lbl?.text = client
        }
    }

    //set the tag for the cell's UIButton equal to the indexPath of the cell
    cell.checkbox_Btn.tag = indexPath.row
    cell.checkbox_Btn.addTarget(self, action: "checkCheckbox:", forControlEvents: UIControlEvents.TouchUpInside)
    cell.checkbox_Btn.selected = task["isCompleted"] as Bool

    if (task["isCompleted"] != nil) {
            cell.checkbox_Btn.setBackgroundImage(UIImage(named:(cell.checkbox_Btn.selected ? "CheckedCheckbox" : "UncheckedCheckbox")), forState:UIControlState.Normal)
    }

    cell.selectionStyle = .None

    return cell

}

func checkCheckbox(sender:UIButton!) {
    var senderBtn:UIButton = sender as UIButton
        println("current row: \(senderBtn.tag)")

    //retrieve the PFObject for the row we have selected
    var task:PFObject = self.taskObjects.objectAtIndex(senderBtn.tag) as PFObject
        println("objectID: \(task.objectId)")

    if task["isCompleted"] as NSObject == true {
            task["isCompleted"] = false
        } else {
            task["isCompleted"] = true
        }

    task.saveInBackgroundWithBlock { (success, error) -> Void in

        if (error == nil) {
            println("saved checkbox object in background")
        } else {
            println(error!.userInfo)
        }
    }

    self.tableView.reloadData()
}

override func tableView(tableView: UITableView?, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

override func tableView(tableView: UITableView?, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    if (editingStyle == UITableViewCellEditingStyle.Delete) {

        var task:PFObject = self.taskObjects.objectAtIndex(indexPath.row) as PFObject

        task.deleteInBackgroundWithBlock({ (success, error) -> Void in

            self.fetchAllObjects()

            self.taskObjects.removeObjectAtIndex(indexPath.row)
        })

    } else if editingStyle == .Insert {

    }
}

person blwinters    schedule 09.02.2015    source источник


Ответы (1)


При работе с таблицами и представлениями коллекций все объекты, которые у вас есть в пользовательской ячейке, могут быть легко доступны в cellForRowAtIndexPath (для UITables).

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("ActionCell", forIndexPath: indexPath) as ActionCell

    var action = actions[indexPath.row] as Action

    cell.nameLabel?.text = action.name
    cell.listLabel?.text = action.list
    cell.dateLabel?.text = action.date
    cell.checkboxButton = action.isChecked
    cell.checkBoxButton.setImage(UIImage(named:"checkedImage"), forState:UIControlState.Normal)
    return cell
}

более того, я бы предложил заменить константы на переменные. Я тоже новичок в Swift, и «let» объявляет статическую переменную.

Я нахожу очень классным использование условного оператора (?:) в этих случаях:

cell.checkBoxButton.setImage(UIImage(named:(any_boolean_condition ? "checkedImage" : "uncheckedImage")), forState:UIControlState.Normal)

поэтому он может вернуть одно имя изображения для условия True и другое имя для условия False.

person Lookaji    schedule 09.02.2015
comment
Спасибо, но я применил ваш код и получил эту ошибку рядом с cell.checkboxButton.setImage... '(UIButton) -> ()' не имеет члена с именем 'setImage' - person blwinters; 10.02.2015
comment
Я предполагаю, что вы путаете некоторые объекты. UIButton имеет метод setImage. Если ваш компилятор говорит, что нет, то переменная, указанная в cell.checkBoxButton, НЕ является UIButton. Другой момент заключается в том, что вы используете логическую переменную self.isChecked, в то время как вы можете использовать состояния UIButton.selected и .isSelected: я бы установил изображение для состояния по умолчанию (непроверенное изображение) и выбранное для последнего состояния, а затем просто переключите UIButton.selected: - person Lookaji; 10.02.2015
comment
В интерфейсе Builder, удерживая нажатой кнопку UIButton, вы должны убедиться, что вы перетащили ссылку из IB в свой код. - person Lookaji; 10.02.2015
comment
если ответ был полезен, пожалуйста, примите его как таковой: D - person Lookaji; 12.02.2015
comment
Очень полезно. Я все еще планирую отредактировать свой вопрос, чтобы показать свой рабочий код будущим сотрудникам Google, но я думаю, что нет причин, по которым я не могу принять его сейчас. Спасибо за вашу помощь. - person blwinters; 12.02.2015
comment
В этом коде функция imageForCheckbox(checkbox:Bool) -> UIImage? { var checkbox = false if checkbox { self.setImage(UIImage(named:checkedImage),forState:UIControlState.Normal) } else { self.setImage(UIImage(named:uncheckedImage),forState:UIControlState.Normal) } } вы используете SELF, но self в этом случае является UITableViewController и, конечно же, не имеет метода setImage. - person Lookaji; 13.02.2015