2017-09-15 47 views
1

我想在我的应用程序中创建一个控制台,以便在屏幕上显示活动或信息。它将以一个简单的字符串“等待新消息...”开始,当不同的事情发生时,新的消息将被添加到该字符串中。当控制台填满时,该字段将随每次添加而滚动,以便用户始终在控制台底部看到最新消息,而旧消息从顶部视图中消失。如何在Swift应用程序中创建最小化控制台(UILabel,UITextView,滚动,截断头?)

是否与“截断头”和一个多行的UILabel的方法吗?我试图先用UILabel做到这一点,但我无法总是查看字符串的END。截断头实际上是一行一行地工作,所以它会显示字符串的前五行,然后显示最后一行可见行的尾部。我尝试了各种对齐和包装设置,但没有任何工作......我错过了什么?有没有办法让UILabel总是显示一个字符串的结尾并让内容从顶部消失?

剪切字符串以适应每次?也许我可以将字符串切成最后一千个字符或类似的字符?但我不知道UILabel会有多大(在不同的屏幕上)...即使我做了,字体是他们的,我怀疑我可以确切地知道我应该修剪字符串的字符数量。我无法将它修剪到给定量的SPACE中,并获得我UILabel中的空间量,对吗?

或者,我可以使用UITextView和滚动也许这是我必须做的。我可以获取文本视图文本的整个值,并将新的字符串添加到UITextView中,然后使用NSMakeRange和.scrollRangeToBottom滚动到底部。

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) 
} 

这似乎是我的小更新控制台的很多工作。我不关心滚动查看过去的值。我甚至更喜欢控制台没有滚动...所以抓住,添加,粘贴,获得底部,然后滚动看起来像很多额外的,不需要的行李。

上实现最小的控制台,使用的UILabel或UITextView的或其他任何方式,欢迎所有的想法,谢谢!

回答

1

我实现了一个“控制台视图控制器”使用的tableview和“ConsoleBuffer”类作为数据源。一个tableview很好地符合消息记录控制台的逐行定位特性,并且使自动滚动变得容易。

ConsoleBuffer是一个单独的类,其保持在字符串和附加了一些辅助功能的一个简单的数组控制台消息。请参阅下面的完整ConsoleBuffer实现:

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() 
    }  
} 

这两句话使ConsoleBuffer单身:

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

有一个单身可以很容易增加新的控制台线项目中的任何位置,而不需要具有的引用该类的一个实例。私下制作init可以防止任何人致电ConsoleBuffer() - 不管您是否被迫使用其单例实例:ConsoleBuffer.shared

控制台线串的buffer阵列是私人保持其执行隐藏举行。当向该数组添加新行时,tableview平滑地滚动到添加的最后一行,但前提是最后一行显示。否则,滚动位置保持不变。

数据源现在是很容易实现:

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 
} 

在的tableview控制器的viewDidLoad功能,你需要的ConsoleBuffertableView属性设置为使用的实现代码如下。此外,这是设置线的期望最大数量的缓存阵列中的存储地点:

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

现在你可以添加新行到控制台这样的:

ConsoleBuffer.shared.add("console message") 

希望这得到你走向正确的方向。

+0

感谢您分享您的实施!我的能力不足以理解你分享的大部分代码,但将控制台消息存储在数组中的概念对我来说是有意义的 - 它会更加强大,并且允许我指定要显示多少在不同的情况下。在尝试类似的东西之前,我需要在Swift中学习更多关于tableViews和数组的知识。再次感谢,D. – Beagley

相关问题