I have a series of dynamically generated EditTexts in an Android Activity. They are generated based on the below XML:
<?xml version="1.0" encoding="utf-8"?>
<EditText
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/customEditText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:cursorVisible="true"
android:textCursorDrawable="#null"
/>
In some circumstances I want to disable them but let them remain visible. I am doing this by setting their focusable property to false (I have reasons for using focusable instead of enabled):
if (view2 is EditText)
{
((EditText)view2).Focusable = false;
}
When I want to reenable the EditText I set the focusable property to true:
foreach (EditText disEditText in m_disabledEditTexts)
{
disEditText.Focusable= true;
}
However, this does not make the EditText respond to the user touching it. I have spent all morning fiddling with this and I haven't been able to solve it! How can I make the EditText responsive again after setting focusable to false.
If the EditText does not have focusable set to false it works fine.
This is written in C# / Xamarin.
You need to also add the FocusableInTouchMode property so it can be focused again in touch mode. Thus said, you should probably set FocusableInTouchMode to true after you've set Focusable to false.
Focus Handling
The framework will handle routine focus movement in response to user input. This includes changing the focus as views are removed or hidden, or as new views become available. Views indicate their willingness to take focus through the isFocusable() method. To change whether a view can take focus, call setFocusable(boolean). When in touch mode (see notes below) views indicate whether they still would like focus via isFocusableInTouchMode() and can change this via setFocusableInTouchMode(boolean).
Focus movement is based on an algorithm which finds the nearest neighbor in a given direction. In rare cases, the default algorithm may not match the intended behavior of the developer. In these situations, you can provide explicit overrides by using these XML attributes in the layout file:
nextFocusDown
nextFocusLeft
nextFocusRight
nextFocusUp
To get a particular view to take focus, call requestFocus().
Reference: http://developer.android.com/reference/android/view/View.htm
Related
I am developing a Android Soft Keyboard. I want to create a layout above the Soft Keyboard. Whenever keyboard show on the screen the layout must visible.
You can easily understand my idea by seeing this image.
As mentioned by Jawad Ahmend in the comments, it's possible to attach the layout to the top of the keyboard by attaching it to the parent bottom using ConstraintLayout. You'd essentially need to do the following steps:
Set the windowSoftInputMode as adjustResize for your activity in the manifest.
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:windowSoftInputMode="adjustResize"
android:theme="#style/AppTheme.NoActionBar">
Set your layout visibility to gone and add a layout constraint attaching it's bottom to the bottom of the parent.
<LinearLayout android:id="#+id/layout_B"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
Next, you need to monitor the soft keyboard state. To keep this short, let's just use the KeyboardVisibilityEvent library. Add the following line to your app's build.gradle and sync it.
implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:2.3.0'
Add a keyboard listener in your activity to set your layout_B to become visible when the keyboard opens and you're done.
KeyboardVisibilityEvent.setEventListener(this) { keyboardIsOpen ->
layout_B.visibility = if (keyboardIsOpen) {
View.VISIBLE
} else {
View.GONE
}
}
If you're writing the keyboard, its easy. Just override onCreateInputView to return the view you want. This can easily be a linear layout with your extra views and the keyboard itself in it.
The bigger problem I see is you have an EditText in there. That's not going to work. Tapping on the EditText is going to break the InputConnection to the actual app and cause... unknown weird behavior. I'm not even sure if the behavior will be defined across different OS versions. It may cause the keyboard to immediately hide. It may cause the keyboard to just stop working at all. The OS isn't meant for that.
I am working with android accessibility. For my requirement i have to get accessibility currently focussed item. i.e. Currently highlighted item in screen.
Something like
if(myButton.isHighlighted)
{
}
I tried all below but nothing workout for me...
if(mybutton.isFocused())
if(mybutton.isSelected())
if(mybutton.isAccessibilityFocused())
if(mybutton.isEnabled())
if(mybutton.isActivated())
if(mybutton.isFocusable())
if(mybutton.isPressed())
You can call isAccessibilityFocused
try these attributes on Button in the layout
android:focusable="true"
android:focusableInTouchMode="true"
and must call inside java file:
mybutton.requestFocus();
After this check, if button is focused with accessibility.
I'm using the new TextInputLayout provided by Android.support to do floating label. But it will fail Espresso Accessibility Check because "View is missing speakable text needed for a screen reader".
Looked into it and find out the TextInputLayout will nullify hint when parent does addView(). This is basically how it can float the label up(set the label, nullify the hint). And any EditText with null hint will fail the accessibility check.
Anyone knows how to resolve this issue? It's really driving me crazy..
Thanks a lot!!!!
A great way to make TextInputLayout accessible is to use "LabelFor" as recommanded by ChrisCM, but you don't have to add an invisible label view to do so: Just put the labelFor or your Textinputlayout and make it point to your EditText
Example:
<android.support.design.widget.TextInputLayout
android:labelFor="#+id/username"
android:contentDescription="#string/username_hint"
android:accessibilityLiveRegion="polite">
<edittext
android:id="#+id/username"
android:hint="#string/username_hint"
…/>
</android.support.design.widget.TextInputLayout>
This way you get the exact same visual behaviour and make "Espresso Accessibility Check" and Talkback happy :)
(To make TextInputLayout fully accessible I also added android:accessibilityliveregion on the TextInputLayout element to trigger talkback whenever the error is poping)
A big thanks to this post this blog post which helped a lot
Hints aren't great for accessibility in general. They disappear when text is entered. Try using a "LabelFor" instead. If you don't want a visible label, you can set your label to not be displayed.
This app will give you hints on how to make text boxes accessible.
https://play.google.com/store/apps/details?id=com.dequesystems.accessibility101
Alternatively, if this is a false positive you can ignore checks as described here
val validator: AccessibilityValidator = AccessibilityChecks.enable().apply {
setSuppressingResultMatcher(
allOf(
matchesCheckNames(`is`("TouchTargetSizeViewCheck")),
matchesViews(withId(R.id.my_overflow))
)
)}
The following rules are invoked when we enable tests for accessibility checks:
TouchTargetSizeViewCheck Target height or target width less than 48
dp is flagged, unless there is a touchdelegate detected.
TextContrastViewCheck Checks text color and background and factors in
large text, and calculates the contrast ratio: - 4.5 for regular
text, 3 for large text.
DuplicateSpeakableTextViewHierarchyCheck If
two Views in a hierarchy have the same speakable text, that could be
confusing for users if at least one of them is clickable.
SpeakableTextPresentViewCheck If the view is focusable, this checks
whether valid speakable text exists, and errors if the view is
missing speakable text needed for a screen reader.
EditableContentDescViewCheck Throws an error if Editable TextView has
a contentDescription.
ClickableSpanViewCheck Checks if ClickableSpan
is inaccessible. Individual spans cannot be selected independently in
a single TextView, and accessibility services are unable to call
ClickableSpan#onClick.
RedundantContentDescViewCheck Accessibility
services are aware of the view's type and can use that information as
needed. For example, it throws a warning if the content description
has a redundant word, such as “button.”
DuplicateClickableBoundsViewCheck Throws an error if Clickable view
has the same bounds as another clickable view (likely a descendent).
Sometimes there are containers marked clickable, and they don't
process any click events.
You can make a TextView that has
android:text="My Announcement For Edit Text"
android:labelFor="#id/my_edit_text".
Visibility = gone and visibility = invisible will make it so this label is not announced. Also if you set height and width to 0dp, this will not announce. Instead, constrain the view to be off the screen using something like:
app:layout_constraintEnd_toStartOf="parent"
So your textview will look like this:
<TextView
android:id="#+id/edit_text_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="#+id/my_edit_text"
android:text="Label For My Edit Text"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
This worked for me using withClassName for a view
AccessibilityChecks.enable().setSuppressingResultMatcher(
AccessibilityCheckResultUtils.matchesViews(
Matchers.anyOf(
ViewMatchers.withResourceName("textview1"),
ViewMatchers.withResourceName("button1"),
ViewMatchers.withClassName(Matchers.endsWith("TextInputLayout"))
)
)
)
I created DialogDragment with several TextEdit. I didn't set focus in xml and java files. But when I call show method and dialog appear I see that focus set in the first text field. How to hide the focus ?
You can set the focus on the surrounding layout instead. by using these attributes:
android:focusable="true"
android:focusableInTouchMode="true"
This will cause the focus to be set on the layout, and not in the EditText.
I have a Preference that enables a sync adapter, and takes a while to actually do its work when toggled. Consequently, when the user clicks the Preference, I spin off an AsyncTask to do the work. In the meantime, I disable the Preference and replace the check box with an indeterminate ProgressBar. I have all of this working via a hack involving a subclass of CheckBoxPreference that overlays the ProgressBar on top of the CheckBox. Yuck.
The android:widgetLayout attribute seems like it's designed exactly for this. I should be able to use android:widgetLayout to specify a replacement for the default CheckBox. Said replacement would implement Checkable and use a ViewSwitcher to switch appropriately between a CheckBox and a ProgressBar.
The only problem is that CheckBoxPreference, in its onBindView() method, seems to ignore the possibility that android:widgetLayout may be used. It explicitly does this:
View checkboxView = view.findViewById(com.android.internal.R.id.checkbox);
This effectively makes it impossible to swap in a custom Checkable via android:widgetLayout and have it actually work.
Is this an oversight/bug in CheckBoxPreference, or have I misunderstood android:widgetLayout? Is there a cleaner intended way to do what I'm trying to do?
First, I agree with you that Android should refactor the piece of code view.findViewById(com.android.internal.R.id.checkbox); to "calling a protected method" which can be overrided by subclass.
Luckily, we are still able to override work around as follows:
The idea is simple: declare a checkbox which has id is android default id #android:id/checkbox
<CheckBoxPreference
android:key="autostart"
android:widgetLayout="#layout/customlayout" />
and in customlayout.xml:
<SwitchView>
...
<CheckBox>
android:id="#android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="mycheck"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
</CheckBox>
It's really important to note that focusable attributes of checkbox must be set to false (I guess the default layout of CheckBoxPreference does the same thing) so that list apdater receives event rather than the checkbox itself.
I guess you didn't success in your try just because you didn't set the focusable state.
greensuisse
(https://sites.google.com/site/greensuisse/)
android:widgetLayout is the right part of the preference. In the CheckBoxPreference, the widgetLayout is the checkbox.
If you take a base Preference and put a ViewSwitcher in the widgetLayout, it should work