- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个表示底层数组的 TableView 。单元格有一个标签和一个 slider , slider 应显示数组的 percentage
属性的值。
我想在百分比属性发生变化时使用键值观察来更新标签。 (我知道 KVO 在这个例子中有点矫枉过正,但最终滑动一个 slider 会影响其他单元格,包括 slider 的位置和底层数组将从应用程序中的多个位置随时设置,所以 KVO 是可行的方法。 )
我得到了很多帮助 from this answer ,但我无法启动它并更新标签。我在这里包括我所有的代码。不知道我哪里错了。
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellDelegate {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for i in 0...4 {
items.append(Items(ID: i, percentage: 50))
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: myTableViewCell.ID) as? myTableViewCell {
cell.object = items[indexPath.row]
cell.mySlider.tag = indexPath.row
return cell
} else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
@IBAction func sliderValueChanged(_ sender: UISlider) {
items[sender.tag].percentage = Double(sender.value)
print("percentage at \(items[sender.tag].ID) is \(items[sender.tag].percentage)")
}
func didUpdateObject(for cell: UITableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .automatic)
print("hello")
}
}
}
class myTableViewCell: UITableViewCell {
static let ID = "myCell"
weak var delegate: CustomCellDelegate?
private var token: NSKeyValueObservation?
var object: Items? {
willSet {
token?.invalidate()
}
didSet {
myLabel.text = "\(object?.percentage ?? 0)"
token = object?.observe(\.percentage) { [weak self] object, change in
if let cell = self {
cell.delegate?.didUpdateObject(for: cell)
}
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var mySlider: UISlider!
}
class Items: NSObject {
let ID: Int
@objc dynamic var percentage: Double
init(ID: Int, percentage: Double){
self.ID = ID
self.percentage = percentage
super.init()
}
}
var items: [Items] = []
protocol CustomCellDelegate: class {
func didUpdateObject(for cell: UITableViewCell)
}
最佳答案
要在 Swift 4 中执行 KVO,您必须将属性声明为 dynamic
并对该对象调用 observe(_:options:changeHandler:)
,保存生成的 NSKeyValueObservation
token 。当该 token 超出范围(或被另一个 token 替换)时,原始观察者将自动删除。
在您的情况下,您让观察者调用委托(delegate),然后委托(delegate)重新加载单元格。但是您似乎从未设置过 delegate
属性,所以我怀疑没有调用该方法。
但这一切似乎都有些脆弱。我倾向于直接在观察者的 changeHandler
中更新标签。我还认为您可以更直接地更新单元格(我将“值已更改”IBAction 放在单元格中,而不是 TableView 中),并消除 tag
的尴尬使用确定模型数组中哪一行的 slider 已更新(如果您插入或删除行,这可能会出现问题)。
所以考虑这个对象:
class CustomObject: NSObject {
let name: String
@objc dynamic var value: Float // this is the property that the custom cell will observe
init(name: String, value: Float) {
self.name = name
self.value = value
super.init()
}
}
然后您可以拥有一个 TableView Controller ,该 Controller 使用此模型类型的实例填充 objects
数组。这里的细节在很大程度上与观察无关(我们将在下面介绍),但我将其包括在内只是为了提供一个完整的示例:
class ViewController: UITableViewController {
var objects: [CustomObject]!
override func viewDidLoad() {
super.viewDidLoad()
// self sizing cells
tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableViewAutomaticDimension
// populate model with random data
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
objects = (0 ..< 1000).map {
CustomObject(name: formatter.string(for: $0)!, value: 0.5)
}
}
}
// MARK: - UITableViewDataSource
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.object = objects[indexPath.row]
return cell
}
}
完成后,您现在可以让单元格的基类 (a) 如果 slider 发生变化,则更新模型对象; (b) 观察 dynamic
属性的变化,在此示例中,当在模型对象中观察到 value
变化时更新标签:
class CustomCell: UITableViewCell {
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var valueLabel: UILabel!
@IBOutlet weak var valueSlider: UISlider!
static private let formatter: NumberFormatter = {
let _formatter = NumberFormatter()
_formatter.maximumFractionDigits = 2
_formatter.minimumFractionDigits = 2
_formatter.minimumIntegerDigits = 1
return _formatter
}()
private var token: NSKeyValueObservation?
weak var object: CustomObject? {
didSet {
let value = object?.value ?? 0
nameLabel.text = object?.name
valueLabel.text = CustomCell.formatter.string(for: value)
valueSlider.value = value
token = object?.observe(\.value) { [weak self] object, change in
self?.valueLabel.text = CustomCell.formatter.string(for: object.value)
}
}
}
@IBAction func didChangeSlider(_ slider: UISlider) {
object?.value = slider.value
}
}
产生:
有关详细信息,请参阅 Using Swift with Cocoa and Objective-C: Adopting Cocoa Patterns 的“键值观察”部分.
关于ios - 如何使用 KVO 根据底层数组元素的变化来更新 tableViewCells?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48009884/
我有以下功能: function addChange(result, bill) { for (var i=0;i
这是网站: www.wearethefirehouse.com/phasetest 如果您慢慢滚动,您会注意到一旦菜单栏完全不透明,nav li 元素就会全部从 Enzo 300 跳起来(如在没有导航
美好的一天。对于当前的项目,我需要知道数据类型如何表示为字节。例如,如果我使用: long three = 500;var bytes = BitConverter.GetBytes(three);
请解释 JVM 是如何在底层收集 ThreadDump 的。 我不明白它如何收集脱离 CPU 的线程的堆栈跟踪(等待磁盘 IO、网络、非自愿上下文切换)。 例如,linux perf 仅收集有关 on
开始学习 R,如果能帮助我理解 R 如何决定不同向量的类别,我将不胜感激。我初始化 vec <- c(1:6)当我执行 class(vec)我得到“整数”。为什么它不是“数字”,因为我认为 R 中的整
我有一个透明的 UIView,几乎覆盖了整个屏幕。我在顶部留下了 50 像素。它是 View Controller View 的 subview 。 在UIView下面有一个继承自UIView的MyV
我很好奇对象是如何在 Nodejs 中显示的,在本例中是 Promise。使用 console.log(promiseObject) 时,输出的类型为 {状态:待处理} 这对我来说似乎很奇怪,因为在该
当您在 Windows Azure 中使用表服务 API 时,幕后到底在做什么?我想我在某处读到这没有使用 SQL Server。它是否执行哈希表,然后过滤器真的像映射/减少操作一样运行?我对这些东西
如何查看函数 concat 中的代码?它是如何做的?有没有人有代码的副本或在浏览器控制台中查看它的方法? console.dir 不给我访问权限 console.dir(Array.prototype
我是 C++ 的新手,所以如果这个问题的答案显而易见,我深表歉意。 我一直在编写 STL 样式的自定义数据结构,以此来提高我的技能。 (我实际上也确实需要这种结构,但出于学习目的,我有点过分了。) 此
我正在尝试使用 log4j appender 将日志发送到 GrayLog2 (log4j2-gelf)。所以我将我的依赖项添加到我的 pom.xml 配置 log4j2.xml 来配置我的 appe
我正在使用带有 vector 的 priority_queue 作为底层容器。但是我希望堆的大小非常大。我知道动态 vector 容量调整大小的问题。所以我正在寻找方法来为我的priority_que
我有一个 SqlDataAdapter,它填充了 21 行数据(4 列)。驱动它的 sproc 在几秒钟内在 SQL Mgmt Studio 中返回,但 .Fill() 需要 5 分钟。 Ar
我想实现一个屏幕控制按钮,按下它可以作为 GUI 交互的修饰符。 这对于 MouseArea 是不可能的,因为该 API 只能处理一个鼠标区域中的一个触摸点。 该限制不适用于 MultiPointTo
我试图将图像和 div 层置于包含 div 的中心,但到目前为止我无法让它从列的左侧移动。我尝试了几种不同的方法,但就是无法让它移动。即使 margin auto 技巧也不起作用,我怀疑这是因为 bo
需要明确的是,我不是在询问 HDFS 中的权限设置,而是在 ext3 中或在 HDFS 运行于其上的各个数据节点机器上使用的任何文件系统中。 p> 我知道我们设置了 sudo chown hduser
我在服务器上创建了一个枚举,其中手动设置了整数值,而不是默认从 0 开始递增 public enum UserType { Anonymous = 0, Customer = 10,
如果显示框架图像,我们能否使以下 Google map 具有交互性。 Vie
我有一个顶部有自定义状态栏的布局 [在 Apple 的状态栏下方],然后是 UIScrollview 在中间部分从左到右分页,然后我有一个 UIView 底部有一些自定义按钮。一个简单的三 Pane
事情是这样的。我有一个 MVC 操作,在该操作上,我应用了自定义 ActionFilterAttribute 来使反序列化工作。现在,我想要做的是根据在此 View 中设置的 ViewBag.Titl
我是一名优秀的程序员,十分优秀!