- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想使用类似 TextView
的东西进行类似串行/TTY/文本终端的同步用户交互。我的意思是我需要以下操作:
Span
设置样式)Span
样式),通过换行符/虚拟键盘上的一些“提交”式按钮等完成。文本的任何其他部分都不应是可选择的、可编辑的等。当然,第二个操作在 UI 线程上没有任何意义,所以按照我的想象,我会有一个单独的线程,其中包含表单的同步代码
// NOT on the UI thread here
textui.addText("What's your name? ",
new StyleSpan(Typeface.BOLD),
new ForegroundColorSpan(Color.RED));
String name = textui.getLine(
new BackgroundColorSpan(Color.GREEN),
new StyleSpan(Typeface.ITALIC));
textui.addText("Hello, ");
textui.addText(name,
new StyleSpan(Typeface.BOLD));
textui.addText("!");
注意 getLine
应该等待用户输入,用户不能编辑 What's your name?
部分,当用户输入时,他的输入应为绿色斜体。这是一些模型:
添加第一行后:
用户开始输入
用户已提交他的输入
我试过的一件事是使用 EditText
和 InputFilter
来拒绝用户编辑,直到调用 getLine
并禁止编辑任何以前的输出,但这仍然允许用户四处移动光标并选择输出,就好像它是输入一样。
编辑添加:由于我的问题“不清楚”,我得到了接近的投票,所以让我尝试用另一种方式解释它。想象一下,您有一个使用 System.out.println
和 System.console().readLine
的控制台程序,并且您想要在 Android 控件(可能包围通过其他 Android 控件),添加样式。
最佳答案
更新:添加了允许/禁止编辑以及指定字段是单行还是多行的标志。将自定义 EditText
移动到单独的类文件中。修复了光标移动问题。
以下是一种可能适合您的方法。我知道您正在寻找一种 TTY 功能。我不确定同步部分是关于什么的,但这里是。
当不允许编辑时,方法是使用自定义 EditText
来消除用户在字段中四处移动的能力,并从硬件键盘检测回车键(字段终止)和禁止删除键。这全部由 TtyEditText.java
中定义的自定义 EditText
完成。
屏幕键盘的控制略有不同,并使用 TextWatcher
来处理事情。
示例应用简单地循环显示三个提示,并使用您在问题中提到的 Spans
类型将用户输入的信息显示回屏幕。
这是一个不允许编辑的快速视频。
使用向左和向右箭头键在字段中四处移动有一个怪癖。右箭头键工作正常,但左箭头键似乎想要在字段之间移动而不是返回字段内。在找到解决方案之前,我已明确禁用这两个功能,即使这是一个问题。
根据 this page :
Users can also navigate your app using the arrow keys on a keyboard (the behavior is the same as when navigating with a D-pad or trackball). The system provides a best-guess as to which view should be given focus in a given direction based on the layout of the views on screen. Sometimes, however, the system might guess wrong.
那么,Android 是不是猜错了?这已通过使已完成的字段不可聚焦来解决。已更正代码以处理光标键。
MainActivity.java
public class MainActivity extends AppCompatActivity
implements TextWatcher, TtyEditText.FieldAction {
private String mPrompts[] = new String[]{
"What is your name? ",
"What is your quest? ",
"What is the air-speed velocity of an unladen swallow? "
};
private int mPromptIndex = -1;
private LinearLayout mLinearLayout;
private TtyEditText mCurrentField;
// true-current field can be edited (backspace/selection); false-disallow field editing
private final boolean mAllowEditing = true;
// true input is single line EditText else multi-line
private final boolean mSingleLine = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
final ScrollView scrollView;
super.onCreate(savedInstanceState);
scrollView = createViewGroup(); // Simple LinearLayout within ScrollView
mLinearLayout = (LinearLayout) scrollView.getChildAt(0);
setContentView(scrollView);
// Get the ball rolling with first prompt.
mCurrentField = generatePrompt(mLinearLayout);
}
// Create the next prompt field and place it at the bottom of the layout.
private TtyEditText generatePrompt(LinearLayout layout) {
final TtyEditText editText;
final SpannableString s;
if (++mPromptIndex >= mPrompts.length) {
mPromptIndex = 0;
}
editText = createTtyEditText(mAllowEditing, mPrompts[mPromptIndex].length());
s = styleText(mPrompts[mPromptIndex], new StyleSpan(Typeface.BOLD),
new ForegroundColorSpan(Color.RED));
editText.setText(s);
layout.addView(editText);
editText.setSingleLine(mSingleLine);
if (!mSingleLine) { // multi-line gets a "done" key.
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
}
editText.addTextChangedListener(MainActivity.this);
editText.requestFocus();
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
return editText;
}
// Echo the user's input to the bottom of the layout.
private void echoResponse(LinearLayout layout, String enteredText) {
final TextView textView = new TextView(this);
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams
(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
SpannableString prefix;
SpannableString input;
prefix = styleText("You entered: ", new StyleSpan(Typeface.NORMAL),
new ForegroundColorSpan(Color.BLACK));
input = styleText(enteredText, new StyleSpan(Typeface.BOLD), new ForegroundColorSpan(Color.BLACK));
textView.setLayoutParams(params);
textView.setTextSize(DEFAULT_TEXT_SIZE);
textView.setText(TextUtils.concat(prefix, input));
layout.addView(textView);
}
// Invoked from our EditText subclass when the enter key is seen on single line EditText and
// from this Activity on multiline EditText.
@Override
public void onEnter(TtyEditText editText) {
final String s = editText.getText().toString();
final String entry = s.substring(editText.getPromptLength(), s.length());
editText.removeTextChangedListener(this);
editText.setFocusable(false);
editText.setFocusableInTouchMode(false);
editText.setEnabled(false);
echoResponse(mLinearLayout, entry);
mCurrentField = generatePrompt(mLinearLayout);
}
@Override
public void afterTextChanged(Editable s) {
// Do nothing
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (mAllowEditing) {
if (start < mPrompts[mPromptIndex].length()) {
mCurrentField.removeTextChangedListener(this); // prevent infinite looping
mCurrentField.setText(s);
mCurrentField.addTextChangedListener(this);
}
} else if (after < count) { // Trying to delete, so don't allow it.
mCurrentField.removeTextChangedListener(this); // prevent infinite looping
mCurrentField.setText(s);
mCurrentField.addTextChangedListener(this);
}
}
// This method only does anything if the input field is multi-line.
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (mSingleLine) {
return;
}
// Multi-line fields get a newline character inserted. Look for the newline, strip it
// and that will complete field entry.
int newlinePos = TextUtils.indexOf(s, "\n");
if (newlinePos != -1) {
mCurrentField.removeTextChangedListener(this); // prevent infinite looping
s = TextUtils.concat(s.subSequence(0, newlinePos),
s.subSequence(newlinePos + 1, s.length()));
mCurrentField.setText(s);
onEnter(mCurrentField);
}
}
// Add text to a TextView (could be an EditText) and apply spans for styling.
private SpannableString styleText(String text, StyleSpan style,
ForegroundColorSpan foregroundColor) {
final SpannableString s = new SpannableString(text);
s.setSpan(style, 0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
s.setSpan(foregroundColor, 0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
s.setSpan(new ForegroundColorSpan(Color.GREEN), s.length(), s.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
s.setSpan(new StyleSpan(Typeface.ITALIC), s.length(), s.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
return s;
}
// Create an empty LinearLayout within ScrollView.
private ScrollView createViewGroup() {
final ScrollView scroll = new ScrollView(this);
final LinearLayout linearLayout = new LinearLayout(this);
final FrameLayout.LayoutParams params =
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
final int margins = convertDpToPixels(16f, this);
params.setMargins(margins, margins, margins, margins);
scroll.setLayoutParams(params);
linearLayout.setLayoutParams(new FrameLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.setOrientation(LinearLayout.VERTICAL);
/* Bottom padding is set here due to a very strange interaction between the
EditText, the soft keyboard, and the ScrollView. With zero padding, when
input field abuts the top of the soft keyboard and the user anter a space,
things get a little wacky with how things are handled. User input freezes and
there are bad calls made to this app. The bottom padding fixes it, though.
*/
linearLayout.setPadding(0, 0, 0, convertDpToPixels(16f, this));
scroll.addView(linearLayout);
return scroll;
}
// Create an instance of our subclass of EditText.
private TtyEditText createTtyEditText(final boolean allowEditing, final int promptLength) {
final TtyEditText editText;
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams
(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
editText = new TtyEditText(this);
editText.setEditParams(allowEditing, promptLength);
editText.setLayoutParams(params);
editText.setTextSize(DEFAULT_TEXT_SIZE);
editText.setBackgroundResource(android.R.color.transparent);
editText.setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
| InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
editText.setPadding(0, 0, 0, 0);
editText.setFocusable(true);
editText.setFocusableInTouchMode(true);
return editText;
}
private static int convertDpToPixels(float dp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
context.getResources().getDisplayMetrics());
}
private static final float DEFAULT_TEXT_SIZE = 18f;
}
TtyEditText.java
public class TtyEditText extends AppCompatEditText {
boolean mAllowEditing = true;
int mPromptLength = 0;
// Interface to activity for the enter key. This can be expanded to accommodate other keys.
FieldAction mFieldAction;
public TtyEditText(Context context) {
this(context, null);
}
public TtyEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TtyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mFieldAction = (FieldAction) context;
}
// Handle the "enter" and "delete" keys from hardware keyboards.
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
mFieldAction.onEnter(this);
return true;
}
super.onKeyDown(keyCode, event);
return false;
}
// Don't let the user move around in the field. If they try, put them back to the end.
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
//on selection move cursor to end of text
if (!mAllowEditing) { // No backspace/no cursor movement except to add to end
setSelection(this.length());
} else if (selStart < mPromptLength && this.getText().length() > 0) { // can't move into prompt area
setSelection(mPromptLength);
} else {
super.onSelectionChanged(selStart, selEnd);
}
}
public void setEditParams(boolean allowEditing, int promptLength) {
mAllowEditing = allowEditing;
mPromptLength = promptLength;
}
public int getPromptLength() {
return mPromptLength;
}
interface FieldAction {
public void onEnter(TtyEditText ttyEditText);
}
}
关于android - 串行(类似 TTY)、与(富) TextView 的同步用户交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41156642/
我正在阅读The TTY demystified ,试图对 tty、pty 有一些了解。 读完前半部分。当我在 xterm 或 ssh 中输入一些命令时,我无法全面了解整个事情是如何工作的。 下图是我
假设我登录到终端 tty1,现在我想从 tty1 运行一个脚本,它会自动让我登录到 tty2、tty3、tty4。当然,我不想到处输入密码和用户名,因为我已经在 tty1 上进行了身份验证。 问题:如
为什么在我将 CentOS 作为 Docker 容器启动后,当我运行 tty 时,我得到: # tty not a tty 不是 tty 的原因是什么? 最佳答案 docker run 不会模拟 TT
我正在尝试通过 php 安装 composer,如他们的网站所述。 php -r "readfile('https://getcomposer.org/installer');" | php 但它显示
我正在运行一个 docker 容器并正在检查它。我发现 "Config": { "Hostname": "amb1.service.consul", "Domainname": "", "User":
我想用 2 个 xterm 窗口调试控制台 linux 应用程序:一个窗口用于 gdb,另一个用于应用程序(例如 mc)。 我现在要做的是在第二个 xterm 窗口中运行“tty && sleep 1
docker exec -it 命令返回以下错误“无法在非 tty 输入上启用 tty 模式” level="fatal" msg="cannot enable tty mode on non tty
这是命令的输出: Step 5/7 : RUN ./vendor/bin/laravel new --force testapp ---> Running in dc92e378b12a Craft
请帮助 MySQL Git Bash winpty mysqldump。 “winpty mysqldump”在 Git Bash 中不工作。这里是错误的详细信息: Git 狂欢 $ winpty m
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 7 年前。 Improve this ques
我一直在试图弄清楚 TTY 驱动程序是如何工作的(充分理解每个内核的实现可能不同),并且偶然发现了一篇不错的文章:The TTY demystified 但是我注意到它声称 xterm 没有 stdi
我正在使用 fork() 和 execvp() 来生成一个进程,该进程必须相信它已连接到交互式终端才能正常运行。 生成后,我想捕获进程的所有输出,并能够将输入发送到进程。 我怀疑 psuedo-tty
我在 ReactJs + 样式组件中遇到这个错误。我该如何解决? Compiled with problems: ERROR in ./node_modules/colorette/index.js
我在 ReactJs + 样式组件中遇到这个错误。我该如何解决? Compiled with problems: ERROR in ./node_modules/colorette/index.js
你好,这是我的脚本: import sys import LED import os import subprocess if __name__ == '__main__': LED_BLUE
我有几个问题。一,如何确定程序使用的 TTY,然后将其作为参数传递给另一个程序? 此外,我正在使用 writevt 程序,并将字符串发送到 TTY 设备。它工作正常,但不使用我发送它的回车符。所以,我
我想从内核空间写入 tty,并且只能访问该特定 tty 的主要和次要设备号。 我通过系统调用进入内核,该系统调用工作正常,并且能够通过使用写入当前 tty my_tty = current->sign
我最近注意到我的系统(运行在 AT91SAM9G15 上)有一个非常奇怪的行为:尽管我一直在读取串行端口,但 TTY 驱动程序有时需要 1.2 秒才能从输入队列传送数据。事情是:我没有丢失任何数据,只
我在没有屏幕的硬件上运行 linux,并将所有数据转储到串口。我正在通过 hyperterm 或 teraterm 等应用程序阅读 linux 序列。我得到了正确格式化的串行输出。但是,如果我将该输出
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我是一名优秀的程序员,十分优秀!