我正在构建一个绘制输入音频数据波形的应用程序。
以下是其外观的直观表示:
它的行为与Apple的原生VoiceMemos应用程序类似。但它缺乏性能。波形本身是一个UIScrollView
子类,我在其中绘制CALayer
的实例来表示紫色''并将它们添加为子图层。开始时波形为空,当声音输入开始时,我用此功能更新波形:
class ScrollingWaveformPlot: UIScrollView {
var offset: CGFloat = 0
var normalColor: UIColor?
var waveforms: [CALayer] = []
var lastBarRect: CGRect?
var kBarWidth: Int = 5
func updateGraph(with value: Float) {
//Create instance
self.lastBarRect = CGRect(x: self.offset,
y: self.frame.height / 2,
width: CGFloat(self.barWidth),
height: -(CGFloat)(value * 2))
let barLayer = CALayer()
barLayer.bounds = self.lastBarRect!
barLayer.position = CGPoint(x: self.offset + CGFloat(self.barWidth) / 2,
y: self.frame.height / 2)
barLayer.backgroundColor = self.normalColor?.cgColor
self.layer.addSublayer(barLayer)
self.waveforms.append(barLayer)
self.offset += 7
}
...
}
当紫色条的最后一个矩形到达屏幕中间时,我开始增加波形的contentOffset.x
以使其保持运行,就像Apple的VoiceMemos应用程序一样。
问题是:当条形数达到~500 ... 1000时,在setContentOffset
期间开始出现一些明显的波形滞后。
self.inputAudioPlot.setContentOffset(CGPoint(x: CGFloat(self.offset) - CGFloat(self.view.frame.width / 2 - 7),y: 0), animated: false)
这里可以优化什么?任何帮助表示赞赏。
答案 0 :(得分:1)
只需删除从超级图层滚出屏幕的条形图。如果你想得到想象,你可以将它们放入队列中以便在添加新样本时重用,但这可能不值得付出努力。
如果您不让用户在该视图中滚动,则根本不值得使用滚动视图,而是在添加新视图时将可见条移动到左侧。
当然,如果您确实需要让用户滚动,您还有更多工作要做。然后,您首先必须存储您在某处显示的所有值,以便您可以将它们取回。使用此功能,您可以覆盖layoutSubviews
以在滚动期间添加所有缺少的栏。
这基本上是UITableView
和UICollectionView
的工作原理,因此您可以使用集合视图和自定义布局来实现此功能。手动完成它可能会更容易,也可以更好地执行。
答案 1 :(得分:0)
我怀疑这可能是一个比你能承受的更大的重构,但SpriteKit可能会给你更好的性能并控制波形的渲染。
您可以使用SpiteNodes(比形状节点快得多)用于波形条。您只需移动包含所有这些精灵的父节点即可实现滚动。
Spritekit非常适合在渲染时跳过非可见节点,如果节点数量成为问题,您甚至可以从场景中动态删除/添加节点。