2017-09-15 4 views
1

Ich möchte eine Konsole in meiner App erstellen, um Aktivitäten oder Informationen auf dem Bildschirm anzuzeigen. Es beginnt mit einer einfachen Zeichenfolge, "Warten auf neue Nachrichten ..." und wenn verschiedene Dinge passieren, werden neue Nachrichten zu dieser Zeichenfolge hinzugefügt. Wenn die Konsole voll ist, scrollt das Feld mit jeder Hinzufügung, so dass der Benutzer immer die letzte Nachricht am unteren Ende der Konsole sieht und alte Nachrichten von der oberen Ansicht verschwinden.Wie erstellt man eine minimale Konsole in einer Swift App (UILabel, UITextView, scrollen, Kopf abschneiden?)

Gibt es einen Weg mit "Truncate Head" und einem mehrzeiligen UILabel? Ich habe versucht, dies zuerst mit UILabel zu tun, aber ich konnte keine Möglichkeit finden, immer das Ende der Zeichenfolge zu sehen. Der abgeschnittene Kopf funktioniert tatsächlich Zeile für Zeile, also würde er mir die ersten fünf Zeilen der Zeichenfolge und dann den Schwanz der letzten sichtbaren Zeile zeigen. Ich habe verschiedene Ausrichtungs- und Verpackungseinstellungen ausprobiert, aber nichts hat funktioniert ... Fehle ich etwas? Gibt es eine Möglichkeit, ein UILabel immer das Ende einer Zeichenkette anzeigen zu lassen und den Inhalt einfach von oben verschwinden zu lassen?

Die Zeichenfolge für jedes Mal ausschneiden? Vielleicht könnte ich nur die Zeichenfolge auf die letzten tausend Zeichen oder ähnliches schneiden? Aber ich weiß nicht, wie groß das UILabel sein wird (auf verschiedenen Bildschirmen) ... und selbst wenn ich das täte, weil die Schriftarten das sind, was sie sind, bezweifle ich, dass ich genau die Anzahl der Zeichen kennen würde, die ich schneiden sollte. Ich kann es nicht auf eine bestimmte Menge von SPACE schneiden und die Menge an Platz in meinem UILabel bekommen, kann ich?

ODER, könnte ich eine UITextView und Scroll Vielleicht ist das, was ich tun muss. Ich kann den gesamten Wert des Textes meiner Textansicht erfassen und den neuen String hinzufügen und ihn wieder in die UITextView einfügen, und dann mit NSMakeRange und .scrollRangeToBottom nach unten scrollen.

func updateConsole(switchType: String) { 

     //unwind the console's text 

     if let tempString = consoleZe.text { 
      currentText = tempString 
     } 

     consoleZe.text = currentText + "A new message here! Something clever taken from \(switchType).\n" 

     //Scroll to the bottom 

     let bottom = NSMakeRange(consoleZe.text.characters.count - 1, 1) 
     consoleZe.scrollRangeToVisible(bottom) 
} 

Das scheint eine Menge Arbeit für meine kleine Update-Konsole. Es ist mir egal, ob ich scrollen kann, um vergangene Werte zu sehen. Ich würde sogar bevorzugen, die Konsole nicht scroll ... So greifen, Hinzufügen, Einfügen, die Unterseite und dann Scrollen scheint wie viel zusätzliches, unerwünschtes Gepäck.

Alle Gedanken über die Implementierung einer minimalen Konsole mit UILabel oder UITextView oder auf andere Weise sind willkommen, danke!

Antwort

1

Ich habe einen "Console View Controller" mit einer Tabellenansicht und einer "ConsoleBuffer" -Klasse als Datenquelle implementiert. Eine Tabellenansicht entspricht gut der zeilenweisen Ausrichtung einer Nachrichtenprotokollierungskonsole und erleichtert das automatische Scrollen.

Die ConsoleBuffer ist eine Singleton-Klasse, die die Konsolenmeldungen in einem einfachen Array von Strings und einigen Hilfsfunktionen enthält. Bitte beachten Sie unter der vollständigen ConsoleBuffer Umsetzung:

class ConsoleBuffer { 
    struct Prefs { 
     static let defaultLines = 100 
     static let maxLines = 1000 
    } 
    static let shared = ConsoleBuffer() 

    private var buffer = [String]() { 
     didSet { 
      if buffer.count > lines { 
       buffer.removeFirst(buffer.count - lines) 
      } 
      tableView?.reloadData() 
      NSAnimationContext.runAnimationGroup({ (context) in 
       if let tableView = self.tableView { 
        if let scrollView = tableView.enclosingScrollView { 
         let range = tableView.rows(in: scrollView.contentView.visibleRect) 
         let lastRow = range.location + range.length 
         if lastRow == oldValue.count - 1 { 
          context.allowsImplicitAnimation = true 
          tableView.scrollRowToVisible(buffer.count - 1) 
         } 
        } 
       } 
      }, completionHandler: nil) 

     } 
    } 

    var lines = ConsoleBuffer.Prefs.defaultLines { 
     didSet { 
      if lines > ConsoleBuffer.Prefs.maxLines { 
       lines = ConsoleBuffer.Prefs.maxLines 
      } 
     } 
    } 

    var count: Int { 
     get { 
      return buffer.count 
     } 
    } 

    var tableView: NSTableView? 

    private init() { } 

    func line(_ n: Int) -> String { 
     if n >= 0 && n < buffer.count { 
      return buffer[n] 
     } else { 
      return "" 
     } 
    } 

    func add(_ line: String) { 
     let dateStampedLine = "\(Date()) \(line)" 
     buffer.append(dateStampedLine) 
    } 

    func clear() { 
     buffer.removeAll() 
    }  
} 

Diese beiden Aussagen ConsoleBuffer machen einen Singleton:

static let shared = ConsoleBuffer() 
private init() { } 

einen Singleton macht es einfach, das Hinzufügen neue Konsolenlinien überall in Ihrem Projekt, ohne die Notwendigkeit von a Verweis auf eine Instanz der Klasse. Wenn Sie init als privat festlegen, wird verhindert, dass jemand anruft. ConsoleBuffer() -aber Sie müssen seine Singleton-Instanz verwenden: ConsoleBuffer.shared.

Die Konsolenstrings werden im Array buffer gehalten, das privat ist, um die Implementierung verborgen zu halten.Wenn Sie diesem Array neue Zeilen hinzufügen, scrollt die Tabellenansicht nahtlos zur zuletzt hinzugefügten Zeile, jedoch nur, wenn zuvor die letzte Zeile angezeigt wurde. Ansonsten bleibt die Scroll-Position unverändert.

Die Datenquelle ist nun einfach zu implementieren:

func numberOfRows(in tableView: NSTableView) -> Int { 
    return ConsoleBuffer.shared.count 
} 

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 
    let cell = tableView.make(withIdentifier: "ConsoleCell", owner: self) as? NSTableCellView 
    cell?.textField?.stringValue = ConsoleBuffer.shared.line(row) 
    return cell 
} 

In der Tableview-Controllers Sie viewDidLoad Funktion verwendet, um die tableView Eigenschaft ConsoleBuffer zum Tableview festlegen müssen. Auch dies ist der Ort, um die gewünschte maximale Anzahl der Zeilen festlegen, die im Puffer-Array zu speichern:

ConsoleBuffer.shared.tableView = tableView 
ConsoleBuffer.shared.lines = 500 

Jetzt können Sie neue Zeilen in die Konsole wie folgt hinzu:

ConsoleBuffer.shared.add("console message") 

Hope this bekommt Du gehst in die richtige Richtung.

+0

Vielen Dank für Ihre Freigabe! Ich bin nicht weit genug in meinen Fähigkeiten, um den meisten Code zu verstehen, den Sie geteilt haben, aber das Konzept, Konsolenmeldungen in einem Array zu speichern, macht für mich Sinn - es wäre viel mächtiger und erlaubt mir genau anzugeben, wie viel angezeigt werden soll unter anderen Umständen. Ich werde in Swift mehr über TableViews und Arrays lernen müssen, bevor ich etwas Ähnliches versuchen kann. Danke nochmal, D. – Beagley

Verwandte Themen