2017-05-28 5 views
2

Ich baue eine App, die die Wellenform von Audio-Eingangsdaten zeichnen.Leistungsoptimierung der Wellenform Zeichnung

Hier ist eine visuelle Darstellung, wie es aussieht:

Es Apples nativen VoiceMemos App in ähnlicher Weise verhält. Aber es fehlt die Leistung. Die Wellenform selbst ist eine UIScrollView Unterklasse, in der ich Instanzen von CALayer zeichne, um violette "Balken" darzustellen und sie als Unterschichten hinzuzufügen. Am Anfang Wellenform leer ist, wenn Toneingang beginnt ich Update-Wellenform mit dieser Funktion:

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 

    } 

... 

} 

Als letzter rect von lila Balken in die Mitte des Bildschirms erreicht beginne ich contentOffset.x der Wellenform zu erhöhen, damit es läuft wie Apples VoiceMemos App

Das Problem ist:, wenn die Anzahl der Balken erreicht ~ 500 ... 1000 einige bemerkenswerte Verzögerung der Wellenform beginnt während setContentOffset passieren.

self.inputAudioPlot.setContentOffset(CGPoint(x: CGFloat(self.offset) - CGFloat(self.view.frame.width/2 - 7),y: 0), animated: false)

Was hier optimiert werden können? Jede Hilfe wird geschätzt.

+0

Sie fügen Subviews _ad infinitum_ hinzu? Wenn ja, müssen Sie dies mit 'UICollectionView' implementieren, damit Ihre Ansichten wiederverwendet werden. –

Antwort

1

Entfernen Sie einfach die Balken, die von ihrem Superlayer scrollt werden. Wenn Sie sich etwas einfallen lassen möchten, können Sie sie in eine Warteschlange stellen, um sie beim Hinzufügen neuer Samples wiederzuverwenden, aber das lohnt sich möglicherweise nicht.

Wenn Sie den Benutzer nicht innerhalb dieser Ansicht scrollen lassen, kann es sich sogar lohnen, keine Bildlaufansicht zu verwenden und stattdessen die sichtbaren Balken nach links zu verschieben, wenn Sie einen neuen hinzufügen.

Natürlich, wenn Sie den Benutzer scrollen müssen, haben Sie noch etwas zu tun. Dann müssen Sie zuerst alle angezeigten Werte speichern, damit Sie sie zurückbekommen können. Damit können Sie layoutSubviews überschreiben, um beim Scrollen alle fehlenden Balken hinzuzufügen.

Dies ist im Grunde funktioniert UITableView und UICollectionView funktioniert, so dass Sie möglicherweise in der Lage, dies mithilfe einer Sammlungsansicht und eines benutzerdefinierten Layouts zu implementieren. Es manuell zu tun, könnte jedoch einfacher und auch ein wenig besser sein.

+0

Vielen Dank für eine Antwort. Haben Sie eine brauchbare Quelle dafür, wie Sie beim Scrollen und Überschreiben von 'layoutSubviews' Ansichten hinzufügen können? Es ist eine Art Geheimnis für mich. –

0

Ich vermute, dass dies wahrscheinlich eine größere Umgestaltung sein wird, als Sie sich leisten können, aber SpriteKit würde Ihnen wahrscheinlich bessere Leistung und Kontrolle über das Rendern der Wellenform geben.

Sie können SpiteNodes (die viel schneller als Formknoten sind) für die Wellenbalken verwenden. Sie können das Scrollen implementieren, indem Sie einfach einen übergeordneten Knoten verschieben, der alle diese Sprites enthält.

Spritekit ist ziemlich gut darin, nicht sichtbare Knoten beim Rendern zu überspringen, und Sie können sogar dynamisch Knoten aus der Szene entfernen/hinzufügen, wenn die Anzahl der Knoten ein Problem wird.