- 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/
在为 Web 应用程序用例图建模时,为用户可以拥有的每个角色创建一个角色是否更好?或拥有一个角色、用户和一个具有特权的矩阵? guest < 用户 < 版主 < 管理员 1: guest 、用户、版主
我无法使用 Elixir 连接到 Postgres: ** (Mix) The database for PhoenixChat.Repo couldn't be created: FATAL 28P
这个问题已经有答案了: Group by field name in Java (7 个回答) 已关闭 7 年前。 我必须编写一个需要 List 的方法并返回 Map> . User包含 Person
感谢您的帮助,首先我将显示代码: $dotaz = "Select * from customers JOIN contracts where customers.user_id ='".$_SESS
我只想向所有用户中的一个用户显示一个按钮。我尝试了 orderByKey() 但没有成功! 用户模型有 id 成员,我尝试使用 orderByChild("id") 但结果相同! 我什至尝试了以下技巧
我们在工作中从 MongoDB 切换到 Postgres,我正在建立一个 BDR 组。 在这一步,我正在考虑安全性并尽可能锁定。因此,我希望设置一个 replication 用户(角色)并让 BDR
export class UserListComponent implements OnInit{ users; constructor(private userService: UserS
我可以使用 Sonata User Bundle 将 FOS 包集成到 sonata Admin 包中。我的登录功能正常。现在我想添加 FOSUserBundle 中的更改密码等功能到 sonata
在 LinkedIn 中创建新应用程序时,我得到 4 个单独的代码: API key 秘钥 OAuth 用户 token OAuth 用户密码 我在 OAuth 流程中使用前两个。 的目的是什么?最后
所以..我几乎解决了所有问题。但现在我要处理另一个问题。我使用了这个连接字符串: SqlConnection con = new SqlConnection(@"Data Source=.\SQLEX
我有一组“用户”和一组“订单”。我想列出每个 user_id 的所有 order_id。 var users = { 0: { user_id: 111, us
我已经为我的Django应用创建了一个用户模型 class User(Model): """ The Authentication model. This contains the u
我被这个问题困住了,找不到解决方案。寻找一些方向。我正在用 laravel 开发一个新的项目,目前正致力于用户认证。我正在使用 Laravels 5.8 身份验证模块。 对密码恢复 View 做了一些
安装后我正在使用ansible配置几台计算机。 为此,我在机器上本地运行 ansible。安装中的“主要”用户通常具有不同的名称。我想将该用户用于诸如 become_user 之类的变量. “主要”用
我正在尝试制作一个运行 syncdb 的批处理文件来创建一个数据库文件,然后使用用户名“admin”和密码“admin”创建一个 super 用户。 到目前为止我的代码: python manage.
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 6 年前。 Improv
我已在 Azure 数据库服务器上设置异地复制。 服务器上运行的数据库之一具有我通过 SSMS 创建的登录名和用户: https://learn.microsoft.com/en-us/azure/s
我有一个 ionic 2 应用程序,正在使用 native FB Login 来检索名称/图片并将其保存到 NativeStorage。流程是我打开WelcomePage、登录并保存数据。从那里,na
这是我的用户身份验证方法: def user_login(request): if request.method == 'POST': username = request.P
我试图获取来自特定用户的所有推文,但是当我迭代在模板中抛出推文时,我得到“User”对象不可迭代 观看次数 tweets = User.objects.get(username__iexact='us
我是一名优秀的程序员,十分优秀!