我正在使用一个具有两个itemSelectedService#setAsSelected()
的iOS应用。第一个是ViewControllers
,它为数组中的每个索引创建一行。 TableView
的每个单元格显示数组中与索引相对应的内容,并具有一个开关。第二个TableView
有一个图像和一个标签,它们应该根据开关状态而改变。那么,如何从特定单元获取开关状态?
ViewController
}
答案 0 :(得分:2)
为开关使用附件视图似乎是一个简单的解决方案,但是访问该视图非常麻烦。 for v in cell?.subviews ?? []
之类的处理标签的事情太可怕了。
更有效的解决方案是自定义单元格类。
在Interface Builder中,将单元格的样式设置为custom
,然后将UILabel
和UISwitch
拖到画布中。将单元格的类别设置为TableViewCell
。
添加一个新的CocoaTouch类TableViewCell
作为UITableViewCell
的子类。您需要两个IBOutlet,一个IBAction和一个callback
变量。回调对于在模型中保持开关状态很重要。连接插座和IB中的操作。
class TableViewCell: UITableViewCell {
@IBOutlet weak var switcher : UISwitch!
@IBOutlet weak var label : UILabel!
var callback : ((Bool)->())?
@IBAction func switchChanged(_ sender : UISwitch) {
callback?(sender.isOn)
}
}
创建一个包含文本和开关状态的数据源模型
struct Item {
var text : String
var isSelected : Bool
init(text : String, isSelected : Bool = false {
self.text = text
self.isSelected = isSelected
}
}
声明数据源数组
var arr : [Item] = [Item(text: "Text1"), Item(text: "Text2"), Item(text: "Text3"), Item(text: "Text4")]
用
代替cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let item = arr[indexPath.row]
cell.label.text = item.text
cell.switcher.isOn = item.isSelected
// the callback updates the model and is called when the value of the switch changes
cell.callback = { newValue in
item.isSelected = newValue
}
return cell
}
将didSelectRow
替换为(是,只有一行,它通过索引路径作为sender
参数)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "segue", sender: indexPath)
}
最终实施prepare(for segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
let viewController = segue.destination as! ViewController // the class of the second view controller
// get the current index path
let indexPath = sender as! IndexPath
let item = arr[indexPath.row]
// get the state of the switch from the model, not from the view
let isSelected = item.isSelected
// do something with `isSelected`
}
}
}
答案 1 :(得分:1)
为了正确实现所需的功能,您将需要设置一个自定义单元。
下面是一个示例,并假定使用了Storyboard / XIB UI:
import UIKit
class SwitchTableViewCell: UITableViewCell {
@IBOutlet weak var textLabel: UILabel!
@IBOutlet weak var contentSwitch: UISwitch!
// So that we can identify the cell in our table view controller.
static let identifier: String {
return String(describing: type(of: self))
}
}
,以便将其用于表格视图。您将必须注册要在SwitchTableViewController.viewDidLoad()
中使用的单元格:
tableView.register(SwitchTableViewCell.self, forCellReuseIdentifier: SwitchTableViewCell.identifier)
接下来,您将要修改cellForRowAt
:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(SwitchTableViewCell.identifier, forIndexPath: indexPath) as! SwitchTableViewCell
cell.textLabel?.text = arr[indexPath.row]
// cell.contentSwitch will be setup as an outlet via Storyboard / XIB.
return cell
}
完成后,继续并将变量添加到SwitchTableViewController
:
fileprivate var selectedState: UIControl.State?
并更新didSelectRowAt
以存储单元格中的状态:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! SwitchTableViewCell
selectedState = cell.contentSwitch.state
segueIdentifier = "segue" // probably want a more meaningful segue name here.
self.performSegue(withIdentifier: segueIdentifier, sender: self)
}
最后,覆盖prepare(for:sender:)
:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
if let vc = segue.destination as? ContentViewController { // cast accordingly, 'ContentViewController' is placeholder
// pass the state to the destination view controller
vc.state = selectedState
selectedState = nil
}
}
}
到此就完成了!
答案 2 :(得分:-1)
有许多方法可以从单元中读取开关的状态。您可以创建一个自定义单元类并使用IBOutlets访问该单元类,甚至可以使用委托从“自定义单元”类返回到View Controller。如果您出于学习目的而使用此代码,则可以像这样在单元格中使用并添加任何类型的控件,但是在实际项目中,您可以尝试使用“自定义”单元格。
查看代码中的注释区域
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var myimg: UIImageView!
var arr: [String] = ["bla", "blablabla", "blabla"]
override func viewDidLoad() {
super.viewDidLoad()
myimg?.image = UIImage(named: "Image1")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default,
reuseIdentifier: "cell")
cell.textLabel?.text = arr[indexPath.row]
let mySwitch = UISwitch()
// Add a tag to your switch so later on you can access the switch using this tag
mySwitch.tag = 1001
cell.accessoryView = mySwitch
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
segueIdentifier = "segue"
// Get the selected Cell and Iterate through it's subviews to find the switch using the tag
let cell = tableView.cellForRow(at: indexPath)
// Iterate through subviews of Cell
for v in cell?.subviews ?? [] {
// If a view found with tag == 1001 then it's the switch view because we had assigned 1001 to the switch view
if v.tag == 1001 {
// One last check we cast the view to UISwitch if it succeed then it's the switch view
if let mySwitch = v as? UISwitch {
// Here you can get the state of the switch
let switchState = mySwitch.state
}
}
}
self.performSegue(withIdentifier: segueIdentifier, sender: self)
}
}
就像我说的那样,这不是使用标签添加和读取视图的最佳方法,但仍然很高兴知道
编辑:
这是您的项目正常运行的完整解决方案。您已经有一个ViewController,但没有要隔离的DetailViewController
查看控制器代码
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let rooms: [String] = ["Kitchen","Living Room", "Master's Bedroom", "Guest's Bedroom"]
let segueIdentifier = "segueIdentifier"
var switch_isOn = false
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rooms.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.text = rooms[indexPath.row]
let mySwitch = UISwitch()
cell.accessoryView = mySwitch
mySwitch.tag = 1001
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get the selected Cell and Iterate through it's subviews to find the switch using the tag
let cell = tableView.cellForRow(at: indexPath)
// Iterate through subviews of Cell
for v in cell?.subviews ?? [] {
// If a view found with tag == 1001 then it's the switch view because we had assigned 1001 to the switch view
if v.tag == 1001 {
// One last check we cast the view to UISwitch if it succeed then it's the switch view
if let mySwitch = v as? UISwitch {
// Assign the current state of the switch to switch_isOn variable
self.switch_isOn = mySwitch.isOn
}
}
}
self.performSegue(withIdentifier: segueIdentifier, sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == segueIdentifier {
if let detailViewController = segue.destination as? DetailViewController {
// used guard let to be on safe side
guard let indexPath = sender as? IndexPath else { return }
// pass in the data needs to the detail view controller
detailViewController.descr = rooms[indexPath.row]
detailViewController.isOn = switch_isOn
}
}
}
}
详细信息视图控制器代码
import UIKit
class DetailViewController: UIViewController {
@IBOutlet weak var descr_label: UILabel!
@IBOutlet weak var state_label: UILabel!
@IBOutlet weak var myImageView: UIImageView!
var descr = ""
var isOn = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
descr_label.text = descr
// for UIImage you can use UIImage(named: "on_image") but i have used the imageLiteral which is pics directly the image from xcassets
myImageView.image = isOn ? #imageLiteral(resourceName: "on_image") : #imageLiteral(resourceName: "off_image")
state_label.text = isOn ? "Switch is ON" : "Switch is Off"
}
}