If there is NO Text typed into TextInputEditText, the Android Accessibility talkback will read the hint in TextInputLayout.
However, Android Talkback will NOT read the hint in TextInputLayout if there is text added into the TextInputEditText.
I Need the Accessibility Talkback to Always read the hint in TextInputLayout.
Does anyone know how to do it?
Thanks guys
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="#+id/editText"
android:hint="username">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>
The only way you can overwrite that it to:
Extend :
public class CustomTextInputLayoutAccessibilityDelegate extends TextInputLayout.AccessibilityDelegate {...}
Then Overwrite:
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
...
// And add the new logic in here:
if (showingText) {
if (hasHint) {
info.setText(String.format("%s, %s", hintText, text));
} else {
info.setText(text);
}
} else if (hasHint) {
info.setText(hintText);
}
}
And set it to your TextInputLayout as:
setTextInputAccessibilityDelegate(new CustomTextInputLayoutAccessibilityDelegate(this));
Related
I put an EditText with inputType="textPassword" in my activity's XML
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Enter Password"
android:inputType="textPassword"
android:padding="16dp"
android:id="#+id/passwordInput"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Till now there is not any problem and I see circles intead of real password characters:
The interesting part is here. Now if I call setSingleLine() on the EditText in the Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
passwordInput.setSingleLine()
}
}
will see that the password characters is surprisingly visible!
Another interesting thing is that this issue will not happen if I put android:singleLine="true" in XML of the EditText.
Note: I know that setting setSingleLine on a password field is useless, but I'm curious why calling this function has such side effect.
I think it is because when you call setSingleLine, textview will change it transformation method from PasswordTransformationMethod to SingleLineTransformationMethod. there is only one transformation method accepted at the time in EditText (which is child of TextView)
you can check the source code here:
setSingleLine()
https://android.googlesource.com/platform/frameworks/base/+/jb-mr0-release/core/java/android/widget/TextView.java#6727
follow through the code fill call function setTransformationMethod
https://android.googlesource.com/platform/frameworks/base/+/jb-mr0-release/core/java/android/widget/TextView.java#1461
Try to set it inside XML:
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"
I can't tell you why setting it programaticaly lead to this strange behavior because I usually do this inside XML and I'm doing this in code just to manipulate Views.
If you want to hide the password, you will:
yourTextView.setTransformationMethod(new PasswordTransformationMethod());
If you want to show the password, you will:
yourTextView.setTransformationMethod(new DoNothingTransformation()), or setTransformationMethod(null)
Method setTransformationMethod is show/hide text
Now, you can check the code of class TextView, Because of EditText extended from TextView.
You will see in the function setSingleLine(), It's call function applySingleLine(singleLine, true, true), This function will set again setTransformationMethod(SingleLineTransformationMethod.getInstance());
This is change your Transformation(show/hide text of EditText):
private void applySingleLine(boolean singleLine, boolean applyTransformation,
boolean changeMaxLines) {
mSingleLine = singleLine;
if (singleLine) {
setLines(1);
setHorizontallyScrolling(true);
// change Transformation
if (applyTransformation) {
setTransformationMethod(SingleLineTransformationMethod.getInstance());
}
} else {
if (changeMaxLines) {
setMaxLines(Integer.MAX_VALUE);
}
setHorizontallyScrolling(false);
if (applyTransformation) {
setTransformationMethod(null);
}
}
}
I have chosen the TextInputEditText for my password field, for using the toggle password feature.
Here is my xml code:
<com.google.android.material.textfield.TextInputLayout
android:layout_width="#dimen/login_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="#dimen/password_margin_top"
app:hintEnabled="false"
app:passwordToggleDrawable="#drawable/password_toggle_drawable"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/my_login_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:hint="#string/password"
android:inputType="textPassword"
android:nextFocusDown="#+id/my_login_login"
android:padding="#dimen/field_padding" />
</com.google.android.material.textfield.TextInputLayout>
I have to do some other layout changes on the toggling password. Is there any callback available for this in TextInputLayout?
You can call setEndIconOnClickListener on your TextInputLayout:
textInputLayout.setEndIconOnClickListener { v ->
// Layout changes here
}
However, this removes the click listener responsible for toggling the password transformation method. I would suggest just copying the click listener code in PasswordToggleEndIconDelegate and adding your own functionality on top:
textInputLayout.setEndIconOnClickListener {
val editText: EditText? = textInputLayout.editText
// Store the current cursor position
val selection = editText?.selectionEnd ?: 0
// Check for existing password transformation
val hasPasswordTransformation = editText?.transformationMethod is PasswordTransformationMethod;
if (hasPasswordTransformation) {
editText?.transformationMethod = null
} else {
editText?.transformationMethod = PasswordTransformationMethod.getInstance()
}
// Restore the cursor position
editText?.setSelection(selection)
// Add additional functionality here
}
Edit: This method is only available in material library version 1.1.0-alpha04 onwards and, as of writing, 1.1.0 is still in beta.
I am trying to change hint text size programmatically, but I just can't find the right method. I'm using setHintTextAppearance, like it's shown in example, but it works only when input is focused or filled with some data. I tried to set EditText textSize also, but still no luck.
textInputLayout.setHintTextAppearance(Vabaco_TextInputLayout_hint_small);
EditText a = textInputLayout.getEditText();
a.setTextSize(8);
You can change hint text size when it unfocused using reflection like this;
try {
Field filed = TextInputLayout.class.getDeclaredField("mCollapsingTextHelper");
filed.setAccessible(true);
Object helper = filed.get(textInputLayout);
Field f1 = helper.getClass().getDeclaredField("mExpandedTextSize");
f1.setAccessible(true);
f1.set(helper,100);
}
catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
name of mExpandedTextSize may be different according to the dependency version for TextInputLayout. You should check TextInputLayout and CollapsingTextHelper classes for the name of variables.
Hope this helps you.
Reflection solution doesn't work on support:design:28.0.0(mExpandedTextSize-> expandedTextSize). Also, Android Q (and later) doesn't support some non-sdk solutions.
Create your custom layout:
public class CustomTextInputLayout extends TextInputLayout {
public CustomTextInputLayout(Context context) {
super(context);
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if(child instanceof EditText) {
((EditText)child).setTextSize(16);
}
super.addView(child, index, params);
}
}
If setting the text size programmatically is not required you can try like below,I have disabled TextInputLayout hint,
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="false">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/edittext"
android:hint="yorhint"
android:inputType="text"
android:textColorHint="#color/colorLightBlack"
android:textSize="10sp" />
</android.support.design.widget.TextInputLayout>
If required programmatically you can find edittext by id and set the text size.
I'm doing my own custom rich text editor in Android using Xamarin, with possibilities of adding/removing bold, underline, italic, color (etc) attributes on the selection. I was losing focus every time I clicked on a button that set one of these attributes so I found the solution with the soft keyboard.
But with the soft keyboard that opens
I can't write more text
even though I have forced the focus on the EditText. The keys pressed do nothing.
Here's the code I'm using to force the soft keyboard to show :
_myEditText.FocusChange += _MyEditText_OnFocusChanged;
and
private void _editor_FocusChange(object sender, FocusChangeEventArgs e)
{
_myEditText.RequestFocus();
InputMethodManager imm = (InputMethodManager)Context.GetSystemService(Context.InputMethodService);
imm.ToggleSoftInput(ShowFlags.Implicit, 0);
}
Is there a way to keep the keyboard open and being able to write new text in the EditText? I've tried with the ShowSoftInput() and the ShowFlags.Forced tag and even the ShowSoftInputOnFocus property on _myEditText but results are the same.
EDIT
I made a sample in Native Android with Android Studio and the keyboard works perfectly OK even without the use of the InputMethodManager ... what am I missing. Is there something in Xamarin that's not working properly ? Because in native it has the exact behaviour that I'm unable to make in xamarin.
EDIT 2
It seems related to the fact I'm using the AppCompat.ViewRenderer of Xamarin.Android and not the basic ViewRenderer. On my way to test it.
EDIT 3
After a long time testing every environment and possibilities, I've come to a conclusion that the code IS working the same way as in a native application but with a custom renderer,
ONLY if my clicks on the buttons are at least ~0.5s long.
If a do an instant click, I lose the focus of my EditText, but if I stay pressed on the button a little longer, the button action is fired, the keyboard stays open and the selection is impacted by the style changement.
Here is some basic code to reproduce the problem as easy as possible.
Just create a basic forms app. And then add the 3 following class
My forms custom view : (empty)
public class RichTextEditor : View
{
}
My android renderer :
using Android.App;
using TestFocusApplicationForms.CustomViews;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(RichTextEditor), typeof(TestFocusApplicationForms.Droid.RichTextEditorRenderer_Droid))]
namespace TestFocusApplicationForms.Droid
{
public class RichTextEditorRenderer_Droid : Xamarin.Forms.Platform.Android.ViewRenderer<RichTextEditor, Android.Views.View>
{
protected override void OnElementChanged(ElementChangedEventArgs<RichTextEditor> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
{
return;
}
if (Control == null)
{
Activity activity = this.Context as Activity;
var view = activity.LayoutInflater.Inflate(Resource.Layout.TestFocus_Layout, this, false);
SetNativeControl(view);
}
}
}
}
And the TestFocus_Layout.axml file corresponding :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="horizontal"
android:layout_gravity="top|end">
<Button
android:layout_gravity="end"
android:layout_width="44dp"
android:layout_height="44dp"
android:text="B"
android:id="#+id/boldButton" />
<Button
android:layout_gravity="end"
android:layout_width="44dp"
android:layout_height="44dp"
android:text="I"
android:id="#+id/italicButton" />
</LinearLayout>
<EditText
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:hint="Texte riche"
android:layout_gravity="bottom"
android:id="#+id/myEditText"
android:singleLine="false"
android:imeOptions="actionNone" />
</LinearLayout>
I've found a solution, it might not be the best in term of long term design but it works.
I made my own VisualElementRenderer for my RichTextEditor Class, and removed all unnecessary code and more important, removed code overriding the default focus behaviour of the element.
Also, it seems the fact that inflating the layout from a .axml file would cause different behaviour as creating the views programmatically, so I made a RichTextEditor_Droid class containing simple conversion of my .axml in C#. And I removed the FocusChange eventHandler on my EditText.
Here is my renderer :
public class RichTextEditorRenderer_Droid :
Xamarin.Forms.Platform.Android.VisualElementRenderer<RichTextEditor>
{
public Android.Views.View NativeView { get; private set; }
public RichTextEditorRenderer_Droid(Context context) : base(context)
{
}
public RichTextEditorRenderer_Droid()
{
}
protected override void OnElementChanged(
ElementChangedEventArgs<RichTextEditor> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
{
return;
}
if (NativeView == null)
{
Xamarin.Forms.Application.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
var activity = Context as Activity;
var textPad = new RichTextEditor_Droid(this.Context);
var textPadLayoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MatchParent,
ViewGroup.LayoutParams.MatchParent);
activity.SetContentView(textPad, textPadLayoutParams);
NativeView = textPad;
}
}
bool _disposed;
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
if (NativeView != null && ManageNativeControlLifetime)
{
RemoveView(NativeView);
NativeView.Dispose();
NativeView = null;
}
_disposed = true;
}
base.Dispose(disposing);
}
}
Now I've got another problem cause I have no more AppBar when this view is rendered on Android. But that is out of context. So thank you #YorkShen-MSFT for helping.
I've opened a bug but i was wondering if anyone encountered this issue and knows a workaround.
If you define a text view with a hint inside it, give it right gravity (android:gravity="right") then if you define android:singleLine=true or android:maxLines="1" or android:scrollHorizonatally="true" you don't see the hint. removing the right gravity returns the hint to the left side, removing all the tree params i mentioned above puts the hint on the right side. i want my hint on the right, but i need a single horizontal line...
here's the sample layout that doesn't show the hint:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<EditText android:layout_width="fill_parent"
android:layout_gravity="center_vertical|right"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:textSize="16sp"
android:paddingRight="5dp"
android:id="#+id/c"
android:gravity="right"
android:hint="hello!!!"
android:scrollHorizontally="true"
android:maxLines="1"
android:singleLine="true"/>
</LinearLayout>
i checked on 1.6 and 2.1 emulators and it reproduces 100%, i'm prettysure it's a bug, i don't see the connection between single line and the hint.... what's more the hint got it's own layout in the TextView (mLayout and mHintLayout both exists, in onDraw if the text length is 0 mHintLayout if mHint is not null is used).
Did you try android:ellipsize="start"? This has worked great for me in the past when I've wanted my hint and EditText to be centered.
Looks like you're exactly right with the issue; I tried playing with your example layout and saw the same issue. I assume this is your bug report.
The easiest solution is to just change your layout, but that's probably not what you want to do. My first attempt at a work around would be to try not setting any of those three attributes in XML and then setting them in Java. If that doesn't work...
One option is to mimic the hint by either extending the EditText class and attempting to fix the code that lays out the hint yourself, or by overriding the onDraw method to create the hint, or perhaps by simply overlapping a regular TextView on top of the EditText, which you then show/hide manually. You could even have the view check if it's empty, and if so set the text to your hint text and change the color. When the view gains focus, check if its text is equal to your hint and, if so, remove the text and change the color back.
Another possible workaround that's a bit more "hacky" is to leave off the three attributes that cause problems, but try to manually prevent a newline from being created. You'd need to create an OnKeyListener for your EditText, something like this:
editText.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
// do nothing
return true;
}
return false;
}
});
You would also want to call editText.setImeOptions(EditorInfo.IME_ACTION_NEXT) to avoid showing the return key. It still may be possible to create a newline in your text field by pasting into it or perhaps some other method, so you would also want to parse and remove newlines when the form is submitted just to be safe. This is also not likely to do what you want as far as horizontal scrolling.
use these properties with hint and single line...u can chnge gravity!!
android:gravity="right"
android:ellipsize="start"
android:imeOptions="actionNext"
android:singleLine="true"
Noting worked good enough for me. When I set Gravity.right, the cursor was always on the right and couldn't be placed in the middle of the word.
I tried a different approach - put the set the gravity the the right when there is no text (or left, if it works for you) and let android decide the best direction once the user entered something
This worked for me:
create TextWatcher class
private static class FilterTextWatcher implements TextWatcher {
private WeakReference<Activity> mActivity;
public FilterTextWatcher(Activity activity) {
mActivity = new WeakReference<Activity>(activity);
}
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (mActivity.get() == null)
return;
EditText searchTxtBx = mActivity.get().mSearchTxtBx;
if (searchTxtBx.getText().toString().length() == 0)
searchTxtBx.setGravity(Gravity.RIGHT);
else
searchTxtBx.setGravity(0);
}
}
use it as class member
private TextWatcher mFilterTextWatcher = new FilterTextWatcher(this);
in onCreate():
mSearchTxtBx.addTextChangedListener(mFilterTextWatcher);
in onDestroy():
mSearchTxtBx.removeTextChangedListener(mFilterTextWatcher);
mFilterTextWatcher = null;
What do you think about my solution to this problem?
editText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus == false && StringUtils.isNotBlank(editText.getText().toString())) {
editText.setGravity(Gravity.RIGHT);
}
}
});
And the corresponding XML File:
<EditText android:id="#+id/the_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="number" android:hint="#string/edit_text_prompt"/>
Works fine for me: just one line, no enter-key possible, shows me the hint and when I leave the field after some input was given, the text appears right-aligned.
it worked with me when I added:
android:hint="the hint text ..."
android:singleLine="true"
android:ellipsize="start"
and in my activity i added :
myedittext.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_ENTER&&event.getAction()==KeyEvent.ACTION_DOWN){
// do nothing
return true;
}
return false;
}
});
I noticed this issue when my TextView atrs are:
android:singleLine="true"
android:gravity="right"
When I try to Linkify the textview or setMovementMethod(LinkMovementMethod.getInstance()) on that textview, the text is just gone.
android:ellipsize="start"
solved my issue, because I use Arabic text in my app.