XCode Swift 4实现类Terminal文本视图:TELNET应用终端交互需求
嘿,针对你开发Telnet简易应用时遇到的类控制台交互问题,我来分享些实用的思路~
先说说当前TextView的问题
你选用的可滚动TextView确实不太适配需求——TextView的isEditable属性是对整个文本块生效的,哪怕你切换状态,它本质上还是把所有文本当成可编辑内容。退格键会往前删除,就是因为它没有区分“不可编辑的历史消息区”和“可编辑的输入区”,所以这种单一组件的方案很难实现你要的效果。
更适配的组件/方案推荐
根据你的需求,这里有几个递进的解决方案:
1. 双组件组合(入门首选,逻辑最清晰)
用两个组件拆分功能:
- 上方用不可编辑的ScrollView+TextView:专门用来展示远程主机发来的消息和本地发送的历史记录,完全禁止编辑,只负责滚动展示。
- 下方用EditText:作为独立的输入框,用户输入内容后,按下回车就把消息发送给远程主机,同时将输入内容追加到上方的历史TextView里。
这种方案的优势是零复杂逻辑,天然隔离了历史和输入区域,完全不会出现误编辑历史的问题,大多数轻量终端类应用都是这么做的。
2. 单一EditText+自定义控制(模拟单一视图效果)
如果你坚持要“单一文本视图”的视觉效果,可以用EditText配合监听器来实现,核心思路是强制区分历史文本和输入文本的边界:
- 每次发送消息后,把内容追加到EditText并换行,记录此时的文本长度(作为历史文本的边界)。
- 通过
TextWatcher监听文本变化,一旦光标试图移到历史文本区域,就强制把光标拉回历史边界之后。 - 拦截退格键,当光标在历史边界位置时,禁止删除前面的历史内容。
给你一段简化的代码示例:
private int historyBoundary = 0; private EditText terminalInput; // 初始化设置 private void initTerminal() { terminalInput.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // 强制光标留在历史边界之后 if (terminalInput.getSelectionStart() < historyBoundary) { terminalInput.setSelection(historyBoundary); } } @Override public void afterTextChanged(Editable s) {} }); // 拦截退格键,防止删除历史 terminalInput.setOnKeyListener((v, keyCode, event) -> { if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { int cursorPos = terminalInput.getSelectionStart(); if (cursorPos <= historyBoundary) { return true; // 消费退格事件,不允许删除历史 } } return false; }); } // 发送消息后的更新逻辑 public void onMessageSent(String message) { // 发送消息到远程主机... // 追加消息到终端并更新历史边界 terminalInput.append(message + "\n"); historyBoundary = terminalInput.getText().length(); }
另外还要注意禁用文本选择功能,防止用户选中历史内容修改,可以通过setCustomSelectionActionModeCallback来实现。
3. 自定义终端组件(专业级定制)
如果追求更贴近原生终端的体验(比如支持光标移动、文本选择仅限制输入区等),可以自己继承View或EditText实现终端组件。核心是维护两个缓冲区:历史消息缓冲区和当前输入缓冲区,绘制时分开渲染,交互时只响应输入缓冲区的编辑操作。不过这个方案复杂度较高,适合需要高度定制的场景。
内容的提问来源于stack exchange,提问作者Nicola
相关产品推荐
相关产品推荐

