I am improving the accessibility for visually impaired in my android app. I have the following TextView in a popover.xml file in my Android project.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:text="#string/pass_code"/>
Whenever I test the app with TalkBack, the app speaks back the string in android:text but in this case I don't want it to be spoken at all because this is a popover window so I would rather want it to be spoken as soon as the window pops over. So I've got android:contentDescription="#string/pass_code" in my root LinearLayout which speaks out the same string.
I've tried to set android:contentDescription="#null" and I've also tried adding tools:ignore="ContentDescription" but neither of them worked. The element in android:text is always spoken. How can I change the TextView so TalkBack will ignore the android:text element?
You can hide a view from accessibility services by setting android:importantForAccessibility="no" in your layout XML. See the developer docs for View.setImportantForAccessibility(int) for more details.
Related
I am working in a kotlin project, and have been searching for some documentation about the screen layout.
What i want to do is very rudimentairy i guess. I want is to put a label/prompt/text before a EditText.
In html i would program something like this:
<form>
<label for="fname">First name:</label>
<input type="text" id="fname" name="fname"><br><br>
</form>
And get the a result like this:
First name: ___________
All i can find is a "android:hint=". But it only fills the View if there is nothing in it.
Should one add extra (plainText) elements for each label ? and how should one contstrain it to the EditText ? or is there some kind of grouping ?
Update after received answers
After reading the answers i understand that you have to roll your own solution. (I am still fighting with androidstudio because it sorts the xml elements so they are not always where i put them.)
I do not use a TextInputLayout (i hope this is allowed) which makes it all quite simple. So this is my solution for now:
We link the TextView ("Date of Birth") to the parent layout:
<TextView
android:id="#+id/dobLabel2"
android:layout_width="92dp"
android:layout_height="23dp"
android:layout_marginStart="76dp"
android:layout_marginBottom="112dp"
android:labelFor="#id/dobInputText"
android:text="Date of Birth"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
and we link the EditText to the TextView
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/dobInputText"
android:layout_width="240dp"
android:layout_height="54dp"
android:hint="Day/Month/Year"
app:layout_constraintStart_toStartOf="#+id/dobLabel2"
app:layout_constraintTop_toBottomOf="#+id/dobLabel2" />
If you play with the layout_contraints you can position the the EditText also to the left of the label.
Thanks for all the input, i think i can solve my problem now.
Android EditText (now often used as a combination of TextInputLayout containing one (and only one) TextInputEditText) can display a Hint, but only while the view has no focus/content.
If you want to provide a better description on what a particular EditText is for, for many reasons (accessibility, often neglected, is not the only one), you may want to provide an extra TextView positioned anywhere you consider it ok to add the extra information needed to better describe the EditText.
The main thing to keep in mind, is to provide this TextView with the labelFor attribute, as described in the Android documentation.
If you're reading this and wondering but why do I have to provide an extra Textview to describe, why not just use the hint, android is horrible!!!, keep in mind that the Hint is good for different reasons, but not for describing what the field is about.
E.g.: Imagine you're asking for a Date of Birth. You may be tempted to write this: (note this is a simplified version obviously):
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/dobInputLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/dobInputText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Date of Birth" />
</com.google.android.material.textfield.TextInputLayout>
And you'd be mostly ok, but then your designer comes in and says, well, we also want to show the Format that we accept, for e.g.: DAY/MONTH/YEAR...
Now you're going to change the hint to be:
android:hint="Date of Birth (DD/MM/YYYY)
And you'd again, be ok, but for accessibility users... this doesn't read very efficiently nor is very clear. You also get back from your designer who says: "but I don't want the (DD/MM/YYYY) part to be visible after the user focuses or types something..."
And so on and so forth.
The correct (according to Google, Material Design, and who knows what), is to provide an extra TextView that accompanies the TextInput combos:
(again, keep in mind this is pseudo-code, when in doubt, read the documentation)
<TextView
android:id="#+id/dobLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date of Birth"
android:labelFor="#id/dobInputText />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/dobInputLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/dobInputText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Day/Month/Year" />
</com.google.android.material.textfield.TextInputLayout>
Do not provide contentDescription on those views because they will likely interfere with TalkBack/Accessibility. These are the conventions that Android set in place, you may or may not like them, but this is how it's expected to be done.
Do I think EditText should be a better widget and handle this better for you? Yes. Does it matter what I think? Nope.
Yes, you have to add one more textview before adding edit text. The hint is used for displaying messages in edittext.
I have an fragment in android TV application which has a lot of TextViews, some of them are focusable and the others are not.
When I turn on the talkback on the device, the views which are not focusable does not get accessibility focus, so their texts are not read to the user.
For example, here is a sample TextView I've inserted to the layout and it is not get focused while on talkback mode:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginBottom="40dp"
android:contentDescription="This is the content description"
android:importantForAccessibility="yes"
android:text="This is the text" />
Of caurse that I don't want to add android:focusable="true" since it will make it focusable also when not on talkback mode.
Is there any thing I am missing that cause this view not to get focus when on talkback mode?
Thanks
You can request focus in talkback mode by following java method.
Trying adding this:
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
from Android P onwards, You can also try this
android:screenReaderFocusable
OR
view.setScreenReaderFocusable(boolean)
I'm using an EditText inside a TextInputLayout, but after upgrading the support library to 23.2.0, I get this warning in the logcat, What's the difference between a regular EditText and a TextInputEditText? I can't seem to find any documentation for it.
I was wondering this too, Daniel Wilson gathered the documentation, but to the untrained eye it doesn't mean much. Here's what it's all about: "extract mode" is referring to the type of view that's shown when the space is too small, for example landscape on a phone. I'm using Galaxy S4 with Google Keyboard as input method editor (IME).
Landscape UI without visible IME
Based on the focus (on Description) you can see TextInputLayout in action pushing the hint outside the editor. Nothing special here, this is what TextInputLayout is supposed to do.
Landscape UI editing empty Name field
Editing the Name you can see that the IME doesn't give you a hint of what you're editing.
Landscape UI editing empty Description field
Editing the Description you can see that the IME gives you a hint of what you're editing.
Layout XMLs
The difference between the two fields is their type EditText VS TextInputEditText. The important thing here is that TextInputLayout has the android:hint and not the wrapped EditText, this is the case when TextInputEditText's few lines of Java code makes a big difference.
Name field
<android.support.design.widget.TextInputLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Item Name"
>
<EditText
android:id="#+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</android.support.design.widget.TextInputLayout>
Description field
<android.support.design.widget.TextInputLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Item Description"
>
<android.support.design.widget.TextInputEditText
android:id="#+id/description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:minLines="4"
android:scrollbars="vertical"
/>
</android.support.design.widget.TextInputLayout>
There is no documentation for it, but the class is a regular EditText with a single extra feature:
Using this class allows us to display a hint in the IME when in 'extract' mode.
Specifically it sets the EditorInfo.hintText. You'll notice in the TextInputLayout class you can specify the hint and it's appearance rather than as part of the child EditText widget.
If you need to do that, you should use a TextInputEditText so it pays attention to the hint info you specified in the TextInputLayout.
They are essentially the same thing, but I think the TextInputEditText has more features and possibly attributes. I changed to the TextInputEditText and everything worked and looked as it did before with the standard EditText.
The only difference is that when your device is in landscape mode, TextInputEditText will show the hint, EditText won't.
I had this problem and just deleted this line in my xml file:
android: fitsSystemWindows = "true"
and the error disappeared.
We're developing an app where we need to use a custom font (a Typeface loaded from the app's assets) in an EditText. The Android input method docs state the following:
When input focus moves into or out of an editable text field, Android shows or hides the input method (such as the on-screen keyboard) as appropriate. The system also makes decisions about how your UI and the text field appear above the input method. For example, when the vertical space on the screen is constrained, the text field might fill all space above the input method.
It's the part in bold that is tripping us up. The phrase “the text field might fill...” appears to be misleading, in that the text field that's used is not the EditText that we set up with our custom font. (NOTE: the answers so far all explain how to set a custom font in an EditText. We already are setting a custom typeface in the EditText. Please read the question carefully before answering.) Here's a screenshot with the input method hidden:
Here's what happens when the soft keyboard is showing and vertical space is constrained:
As you can see, the font in the text field above the input method is not our custom font (I'm guessing it's the system's default Roboto font). This is happening for every soft keyboard we've tried as the input method.
I want to emphasize that when space is constrained, this view above the keyboard is generated internally by the system, not by any of our code.
The main question is: Is there a way (and, if so, what is it?) to control the appearance of this (for lack of better terminology) proxy view—at a minimum to get it to use our custom font?
It would be an added bonus if we could also control the layout and appearance of the entire proxy area above the keyboard (including the "Done" button). We are using a variation of the technique described in this thread to have our activity use a locale different from the one set in the system, but the activity's locale clearly isn't being applied here. (If it were, the button would be on the left and would read "בוצע", as does happen if I change the device's locale to Hebrew. [EDIT: I can get the correct button label by using the android:imeActionLabel attribute on the EditText. However, I don't know how to control the layout directionality.])
EDIT Per request, here's how I'm constructing my dialog (relevant parts excerpted from a DialogFragment):
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Dialog dlg = new Dialog(getActivity(), android.R.style.Theme_Holo_Light_Dialog_NoActionBar);
dlg.setContentView(R.layout.edit_note_dialog);
mAnimator = (ViewAnimator) dlg.findViewById(R.id.animator);
final Typeface hebrew = SystemData.getHebrewFont();
mNoteEditor = (EditText) dlg.findViewById(R.id.note_field);
mNoteEditor.setTypeface(hebrew);
// etc. (setting fonts for other elements, adding listeners, etc.)
}
And here's the layout:
<?xml version="1.0" encoding="utf-8"?>
<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/animator"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingTop="10dp"
android:text="#string/loading" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="#android:color/black"
android:gravity="center"
android:text="#string/edit_note_title"
android:textColor="#android:color/white"
android:textSize="20sp" />
<TextView
android:id="#+id/citation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/title"
android:layout_centerHorizontal="true"
android:background="#android:color/black"
android:gravity="center"
android:textColor="#android:color/white"
android:textSize="16sp" />
<LinearLayout
android:id="#+id/actions"
style="?android:attr/buttonBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_margin="5dp" >
<Button
android:id="#+id/cancel"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center"
android:minWidth="32dp"
android:text="#string/cancel"
android:textSize="#dimen/nav_interior_item_size" />
<Button
android:id="#+id/close"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:gravity="center"
android:minWidth="32dp"
android:text="#string/save"
android:textSize="#dimen/nav_interior_item_size" />
</LinearLayout>
<Button
android:id="#+id/undo"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_margin="5dp"
android:text="#string/edit_note_undo"
android:textSize="#dimen/nav_interior_item_size" />
<Button
android:id="#+id/redo"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_margin="5dp"
android:text="#string/edit_note_redo"
android:textSize="#dimen/nav_interior_item_size" />
<EditText
android:id="#+id/note_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/actions"
android:layout_below="#+id/citation"
android:focusableInTouchMode="true"
android:gravity="top"
android:hint="#string/edit_note_hint"
android:imeActionLabel="#string/done"
android:inputType="textMultiLine|textNoSuggestions"
android:lineSpacingMultiplier="1.2" />
</RelativeLayout>
</ViewAnimator>
It would be simple if you had an instance of InputMethodService.
There is a way to set a theme or even set extracted view.
The problem is you have to create a custom implementation of Input Method and users will have to select it in the system settings.
Update:
You can try with:
android:windowSoftInputMode="adjustResize"
make the view scrollable
or
use IME_FLAG_NO_EXTRACT_UI
set an OnEditorActionListener on the EditText to have an action button on the keyboard.
create custom layout or hide/show elements when screen's height is too small. For example hide buttons at the bottom and show buttons on right side. It can look similar to the default extract view.
layout listener for the dialog or EditText:
mViewContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//unregister the layout listener if needed.
int heightPixels = mViewContainer.getHeight();
Resources resources = mContext.getResources();
int heightDip = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightPixels, resources.getDisplayMetrics());
if (heightDip < MIN_HEIGHT) {
mBottomButtons.setVisibility(View.GONE);
mSideButtons.setVisibility(View.VISIBLE);
} else {
mBottomButtons.setVisibility(View.VISIBLE);
mSideButtons.setVisibility(View.GONE);
}
}
});
Changing the visibility to GONE will request relayout and the listener will run again what can lead to a loop.
The only way I can see is to disable the fullscreen editing mode for your EditText that automatically kicks in when your EditText is not tall enough.
mNoteEditor.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
You can fix the dialog resizing issues with
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
Your dialog layout should probably be enclosed in a ScrollView.
I think as other have stated this is unfortunately up the IME and may not be possible through supported APIs.
Beware, hacky and untested solution incoming:
Digging through the Android source code, I found that every IME contains an implementation of AbstractInputMethodService. Android provides a standard implementation (android.inputmethodservice.InputMethodService) which if you look at, has a public setExtractView method, and an onCreateExtractTextView method, which inflates com.android.internal.R.layout.input_method_extract_view.xml, which in turn contains com.android.internal.R.id.inputExtractEditText! So a hacky solution would be to hope that most of your customer's IMEs' InputMethodServices use this same XML (which as far as I can tell, has been in Android for a while), and you can attempt to grab a reference to this EditText by it's ID and change it's typeface. Unfortunately I'm not sure offhand where in the view hierarchy/window the views of an InputMethodService are added, and if they're accessible from your app/activitys process.
Source for InputMethodService:
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/inputmethodservice/InputMethodService.java
Source for the layout XML:
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/input_method_extract_view.xml
If you really want to get yourself in trouble, perhaps there's a way to get a reference to the IME service itself, and use reflection to alter the extracted view. The standard InputMethodService holds a package-private reference to mExtractEditText :)
I know not the answer you're looking for but perhaps it'll put you in the right direction...or some direction at least.
If you have a single editable element on your Dialog, how about handling orientation changes and
in case of Portrait orientation, show the Dialog
in case of Landscape orientation, show a fullscreen Fragment with the EditText and Buttons (as others have stated; disable fullscreen editing mode for the EditText), request focus for the EditText, show Keyboard.
in case of orientation switching dismiss Dialog / show Fragment with the already entered text (and vice versa)
This might be conceptually good because if the user wishes to enter text, he/she will always end up in a fullscreen editing layout in Landscape orientation. And since there is only one editable view in the original Dialog, you don't explicitly need the Dialog to select anything else to edit (another EditText for example).
I have a text field and when I use the IME (the default one for Nexus One) it doesn't display the auto-suggest line on top of the soft keyboard.
Ironically there are posts here on how to prevent the auto-suggest, but in my case it's the revert, it doesn't show up and it's not clear why.
Here's my layout tag. I'm in API 8.
<EditText
android:id="#+id/user_text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="top"
android:singleLine="false"
android:inputType="textLongMessage|textCapSentences|textMultiLine|textAutoCorrect|textAutoComplete"
android:hint="#string/errorreport_user_hint"
android:paddingLeft="5dip"
android:paddingRight="5dip"
/>
Ah got it, I should not use the textAutoCorrect flag.
I thought it would ask the IME to display auto-correction, instead the doc indicates it means the editor is providing auto-corrections (I guess such as AutoCompleteEditText) and thus the IME should not display the auto-suggests.