Ios 如何在视图不闪烁的情况下删除和添加ArrangedSubvew?
我有一些从一个stackview组成的视图。每隔Ios 如何在视图不闪烁的情况下删除和添加ArrangedSubvew?,ios,swift,uiview,uistackview,Ios,Swift,Uiview,Uistackview,我有一些从一个stackview组成的视图。每隔n秒,我都应该用服务器上的数据更新此视图。当新数据出现时,我清理stackView(使用其子级的方法removeFromSuperView)并再次添加ArrangedSubview以更新UI。有时,服务器发送与旧数据相同的数据。但在做这个更新操作时,我的观点有点不寒而栗。每次我清理并向stackview添加视图时,它都有点拖拉和颤抖。当然,我只能在oldData!=新数据。但这种竞争很难找到正确的答案。那么,如何使用新数据更新stackview而不
n
秒,我都应该用服务器上的数据更新此视图。当新数据出现时,我清理stackView(使用其子级的方法removeFromSuperView)并再次添加ArrangedSubview以更新UI。有时,服务器发送与旧数据相同的数据。但在做这个更新操作时,我的观点有点不寒而栗。每次我清理并向stackview添加视图时,它都有点拖拉和颤抖。当然,我只能在oldData!=新数据。但这种竞争很难找到正确的答案。那么,如何使用新数据更新stackview而不抖动和闪烁
这是我的密码:
func configure(_ items: [Item]) {
stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
items.forEach {
let someView = SomeView()
someView.configure($0)
stackView.addArrangedSubview(someView)
}
}
而不是删除/重新添加视图到堆栈视图
- 仅当项目多于当前排列的子视图时,才添加新视图
- 设置数据-
-每个排列的子视图configure()
- 如果现有排列的子视图超过需要,则隐藏现有排列的子视图
func configure(_ items: [Item]) {
// if we have fewer arranged subviews than items
// add new ones
while stackView.arrangedSubviews.count < items.count {
stackView.addArrangedSubview(SomeView())
}
// hide any existing arranged subviews if we have too many
for i in 0..<stackView.arrangedSubviews.count {
stackView.arrangedSubviews[i].isHidden = i >= items.count
}
// update the existing arranged subviews with the new data
for (thisItem, thisView) in zip(items, stackView.arrangedSubviews) {
// unwrap the arranged subview
guard let v = thisView as? SomeView else {
continue
}
v.configure(thisItem)
}
}
带有两个标签的示例“SomeView”类:
class SomeView: UIView {
let titleLabel = UILabel()
let descLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
backgroundColor = .systemYellow
titleLabel.font = .boldSystemFont(ofSize: 18.0)
descLabel.font = .italicSystemFont(ofSize: 15.0)
[titleLabel, descLabel].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .white // so we can see the label frames at run-time
addSubview(v)
}
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
descLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4.0),
descLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
descLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
descLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
])
}
func configure(_ item: Item) -> Void {
titleLabel.text = item.title
descLabel.text = item.desc
}
}
带有堆栈视图的示例“NeoView”类:
class NeoView: UIView {
let stackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 8
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
])
}
func configure(_ items: [Item]) {
// if we have fewer arranged subviews than items
// add new ones
while stackView.arrangedSubviews.count < items.count {
stackView.addArrangedSubview(SomeView())
}
// hide any existing arranged subviews if we have too many
for i in 0..<stackView.arrangedSubviews.count {
stackView.arrangedSubviews[i].isHidden = i >= items.count
}
// update the existing arranged subviews with the new data
for (thisItem, thisView) in zip(items, stackView.arrangedSubviews) {
// unwrap the arranged subview
guard let v = thisView as? SomeView else {
continue
}
v.configure(thisItem)
}
}
}
为什么要重新创建视图?为什么您不能只创建一次,并保持对这些视图的引用,并每n秒更新一次,这样视图将在不闪烁的情况下更新。支持,我保持引用并将其存储为数组,如[SomeView]。但下一次更新的数据的长度大于[SomeView]长度。如您所见,无论如何,我应该重新创建视图。为什么不使用
UICollectionView
(或者UITableView
)呢?这些设计用于(取消)当前不可能的视图队列。因为所有的项目都在类似卡片的视图中。是否可以将tableview放在类似卡片的视图中,并使卡片的高度适合tableview?我现在不知道。@neo-什么是SomeView
?您不必删除和添加所有排列的子视图来更新它们。如果您向我们展示什么是SomeView
(以及Item
是什么),我可以向您展示更好的方法。
class NeoView: UIView {
let stackView: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 8
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
])
}
func configure(_ items: [Item]) {
// if we have fewer arranged subviews than items
// add new ones
while stackView.arrangedSubviews.count < items.count {
stackView.addArrangedSubview(SomeView())
}
// hide any existing arranged subviews if we have too many
for i in 0..<stackView.arrangedSubviews.count {
stackView.arrangedSubviews[i].isHidden = i >= items.count
}
// update the existing arranged subviews with the new data
for (thisItem, thisView) in zip(items, stackView.arrangedSubviews) {
// unwrap the arranged subview
guard let v = thisView as? SomeView else {
continue
}
v.configure(thisItem)
}
}
}
class NeoTestViewController: UIViewController {
let neoView: NeoView = {
let v = NeoView()
v.backgroundColor = .systemTeal
return v
}()
var items: [[Item]] = []
var idx: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
neoView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(neoView)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
neoView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
neoView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
neoView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
// no bottom constraint
])
items = sampleData()
var idx: Int = 0
self.neoView.configure(self.items[idx % self.items.count])
// update neoView with a new set of items every 1.5 seconds
Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { timer in
idx += 1
self.neoView.configure(self.items[idx % self.items.count])
}
}
func sampleData() -> [[Item]] {
// we'll create 8 sets of [Item] arrays
// each with a different number of Items
let numItems: [Int] = [
4, 2, 6, 3, 7, 8, 3, 5,
]
var items: [[Item]] = []
var i: Int = 1
numItems.forEach { n in
var theseItems: [Item] = []
for j in 1...n {
let thisItem = Item(title: "Set \(i) item \(j) title.", desc: "Set \(i) item \(j) description.")
theseItems.append(thisItem)
}
theseItems[0].title = "Set \(i) has \(n) items."
items.append(theseItems)
i += 1
}
return items
}
}