AccessibilityTraversalBefore doesn't work with talkback - android-layout

I have a recycler view with a list of items. This is how it looks:
I need to add Talkback support. The problem is with the order of focusing inside recycler item view.
This should the correct order:
1. Name of first member (A)
2. Amount under first member's name (2469...)
3. Name of second member (B)
4. Amount under second member's name (2469...)
The problem is that default focus order is different:
1) Name of the first member
2) Name of the second member
3) Amount under the first member
4) Amount under the second member
The solution should be pretty easy. There is a parameter android:accessibilityTraversalBefore="#+id/someID" which change the order of focus. I use this parameter in other views in my app without a problem - it works nice. However when I use it here it doesn't have any effect at all - the views are still focused in the default order.
Let's take a look at recycler item layout:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="56dp">
<android.support.constraint.Guideline
android:id="#+id/vGuideline"
style="#style/Layout.Guideline"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5"/>
<android.support.v7.widget.AppCompatImageView
android:id="#+id/vFirstAvatar"
style="#style/Image.AvatarMember"
app:layout_constraintBottom_toBottomOf="parent"
tools:src="#drawable/avatar_multiple" />
<!-- Ellipsized because it can overlay the second member. -->
<android.support.v7.widget.AppCompatTextView
android:id="#+id/vFirstName"
style="#style/TextView.NameEllipsized"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="11dp"
android:layout_marginEnd="8dp"
android:importantForAccessibility="yes"
android:layout_marginRight="8dp"
android:accessibilityTraversalBefore="#+id/vFirstAmount"
android:textAppearance="#style/ListPrimaryTiny"
app:layout_constraintLeft_toRightOf="#+id/vFirstAvatar"
app:layout_constraintRight_toLeftOf="#+id/vGuideline"
app:layout_constraintTop_toTopOf="parent"
tools:text="Suzan" />
<!-- Ellipsized because it can overlay the second member. -->
<android.support.v7.widget.AppCompatTextView
android:id="#+id/vFirstAmount"
style="#style/TextView.NameEllipsized"
android:layout_marginTop="2dp"
android:accessibilityTraversalBefore="#+id/vSecondName"
android:textAppearance="#style/ListSecondary"
android:importantForAccessibility="yes"
app:layout_constraintLeft_toLeftOf="#+id/vFirstName"
app:layout_constraintRight_toRightOf="#id/vGuideline"
app:layout_constraintTop_toBottomOf="#+id/vFirstName"
tools:text="$22" />
<android.support.v7.widget.AppCompatImageView
android:id="#+id/vSecondAvatar"
style="#style/Image.Avatar"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/avatar_multiple" />
<!-- Ellipsized because it can overlay first member. -->
<android.support.v7.widget.AppCompatTextView
android:id="#+id/vSecondName"
style="#style/TextView.NameEllipsized"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:importantForAccessibility="yes"
android:accessibilityTraversalBefore="#+id/vSecondAmount"
android:layout_marginTop="11dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:gravity="end"
android:textAppearance="#style/ListPrimaryTiny"
app:layout_constraintLeft_toLeftOf="#+id/vGuideline"
app:layout_constraintRight_toLeftOf="#+id/vSecondAvatar"
app:layout_constraintTop_toTopOf="parent"
tools:text="Dave" />
<!-- Ellipsized because it can overlay the first member. -->
<android.support.v7.widget.AppCompatTextView
android:id="#+id/vSecondAmount"
style="#style/TextView.NameEllipsized"
android:layout_marginTop="2dp"
android:importantForAccessibility="yes"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:gravity="end"
android:textAppearance="#style/ListSecondary"
app:layout_constraintRight_toRightOf="#+id/vSecondName"
app:layout_constraintLeft_toLeftOf="#id/vGuideline"
app:layout_constraintTop_toBottomOf="#+id/vSecondName"
tools:text="$8" />
</android.support.constraint.ConstraintLayout>
Do you have any idea what is the reason why Talkback completely ignores
AccessibilityTraversalBefore attribute?

If you look at the OrderedTraversalController in the "TalkBack" project, you can see that TalkBack does in fact respect this property. I appologize, but I don't have time to set up a test for this and confirm, but my guess would be that setting this up in XML isn't going to work. It is likely that the recycler view is overriding the XML property at run time.
Try doing it in code after all the views have rendered. Probably a few race conditions involved as well! I don't actually know what callback you would have to use to get this to happen reliably. I may investigate more later.

Related

Layout in Android Emulator looks different as compared to the layout file

I have recently started learning Android Development. I am using Android Studio and I created the XML layout file with it. But the layout is looking different on the emulator to the one I created on XML and I have no clue why it is happening.
This is the picture of my Main activity layout:
And this is the picture of my emulator:
The plain text should be below the text view but in the emulator, its position is different(I have marked the error by red).
Here is the code for the Main activity:
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="208dp"
android:text="SUBMIT"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="80dp"
app:layout_constraintBottom_toTopOf="#+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="44dp"
android:text="Enter the value in kg below"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/editTextNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
tools:layout_editor_absoluteX="100dp"
tools:layout_editor_absoluteY="73dp" />
I'm not sure why it is showing that way in the emulator versus the preview, but the reason that the EditText field isn't where you want it to be is because of how you have set the position of the editTextNumber field:
tools:layout_editor_absoluteX="100dp"
tools:layout_editor_absoluteY="73dp"
You are telling Android to position the field 100 pixels in and 73 pixels down from the top of the screen. Most than likely this occurred because you accidentally dragged the field slightly in the editor window, which specifies the exact pixel placement.
Instead, since you are using a ConstraintLayout, you'll want to set the location of the EditText in relation to other fields on your layout. For example, remove the two lines above and replace them with something like this:
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView"
I would also suggest that you name your fields on the layout with descriptions of what they represent, rather than the defaults of textView and textView2. For example, consider changing textView2 to something like weight_label_textview. It will make it much easier to know which field you are dealing with both in the layout and in your code.
As you are using constraint layout every UI item must constraint vertical and horizontally. Try adding constraints to your EditText.

Can't constrain an element to a barrier

I'm having an issue where I'm trying to constrain a button to a vertical barrier. When I drag the button's side that I want to constrain to the barrier, it doesn't seem to recognise the barrier. It doesn't snap onto it or apply any constraint after hovering onto it and letting go.
I've tried replicating a simple tutorial from YouTube, where he constrains his button to the barrier with no issue at the time stamped link: https://youtu.be/Ngz5cgLC7m4?t=180.
I'm aware you can add the barrier ID to the Button's XML's left contraint. But it doesn't exactly fix the underlying issue.
I've also checked my version's current changelog on barriers (nothing changed).
edit: here's my XML file:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView4" />
<android.support.constraint.Barrier
android:id="#+id/barrier3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="textView5,textView4"
tools:layout_editor_absoluteX="411dp" />
<Button
android:id="#+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="173dp"
tools:layout_editor_absoluteY="64dp" />
</android.support.constraint.ConstraintLayout>
Some minor problems come with the Graphical design editor like you can't be 100% sure that it didn't use absoluteX and absoluteY instead of Constraints. I always prefer the text editor because you know the code as you can see the code and modify it as you want.
So, I checked your code and saw that you're using absoluteX and absoluteY instead of Constraints for the button. You can constrain it to the barrier as
<Button
android:id="#+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
//These two constraints will set the position on Horizontal axis
app:layout_constraintStart_toEndOf="#id/barrier3"
app:layout_constraintEnd_toEndOf="parent"
//You should replace it as well with constraints.
tools:layout_editor_absoluteY="64dp" />
Now, as you can see I've replaced absoluteX with Start_toEndOf and End_toEndOf. Now, to set vertical constraints, I don't actually understand why is y's position 64dp, but you can do one thing. Either constrain it with Top and use it as marginTop from Top or You can use Vertical Bias.
You can replace absoluteY with this:
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.1"
Vertical_bias 0.1 will give you similar result, it will postition your button to 10% of the screen size and it's dynamic which means it will be on same position on any screen size.
Just Change your code with this and I hope you'll have your answer. You can ask anything else if needed.

How to add constrainlayout only to floating actio button?

I want to add constrainlayout only two the last two floating action button with nested framelayout. any help would be highly appreciated. My main idea is to able to move and position the floating action button from graphical user interface.
I have notice that android gravity help to put button at right and the center from right with
android:layout_gravity="right|center"
how can i add a button at right but between center and end at bottom.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000000"
tools:context=".MediaPresentationActivity"
android:id="#+id/FrameLayout">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/videoViewPresentation"
android:layout_gravity="center" />
<ImageView
android:id="#+id/imageViewPresentation"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="left|top"
android:background="#ffffff"
android:src="#drawable/serv24logobig" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</LinearLayout>
//*how to add only below two floating action button as constrainlayout //
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="right|center"
android:src="#android:drawable/stat_sys_phone_call"
android:visibility="visible"
app:backgroundTint="#android:color/holo_red_dark"
app:elevation="12dp"
app:rippleColor="?android:attr/colorActivatedHighlight" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="right|center"
android:src="#android:drawable/stat_sys_phone_call"
android:visibility="visible"
app:backgroundTint="?android:attr/colorMultiSelectHighlight"
app:elevation="12dp"
app:rippleColor="?android:attr/colorActivatedHighlight" />
</FrameLayout>
FrameLayouts only allow ONE child (well they allow N children, but they overlap, because it doesn't support children positioning, rather it expects them to take all the available space), so if you want to use a ConstraintLayout to position two items inside a FrameLayout, then you need to ensure that the children of your FrameLayout, is a ViewGroup that allows positioning of its own children.
Let's see what you got.
Your Root is a FrameLayout, perhaps you should consider making it a ConstraintLayout to begin with...
You're asking your Root layout to wrap its contents. Unless this is a custom view, this is somewhat frowning, but not wrong; since I don't know how you're using this, it's hard to tell if this is the correct approach in this case.
I don't know how your UI should look, but from what I see, you have a series of nested LinearLayouts, Vertical, then Horizontal to have an ImageView and a VideoView... not sure how you expect these to be positioned.
Down Below you have an empty LinearLayout... (?)
and then you tossed the two FABs.
This is not going to work. I suggest you revisit your entire Layout (which, btw, is incorrect as pasted, because you're closing the FrameLayout twice...).
If you post an image of what your desired output is, perhaps we can help you better understand where your problem is. As it is, it's not possible to determine.
The answer to your question, as written at this time is:
"How can I add a constraint Layout onlo to the last two FABs?"
You can't (for the purposes I think you want), but if you really want to see why, and what would happen:
Simply add, inside your FrameLayout this:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<!-- YOUR FABS GO HERE -->
</androidx.constraintlayout.widget.ConstraintLayout>
This will obviously NOT LOOK THE WAY YOU WANT, but that's why I asked you in the comment above, "show us what you want, we need a minimal reproducible example of what you need".
There was a reason why I asked that, not to annoy you, but to help you. You chose to ignore it, and that's as far as I can go to help you with the information I have.

Android clickable layouts above empty views

My project also uses Xamarin with MvvmCross, but I don't think this will effect the answer since the problem is all view-layout/axml related.
I have a GridView that summarizes a list of contacts. When clicking on this grid view, I would like the user to be taken to another screen to add more contacts to this list (so there is more space).
Subscribing to the GridView's OnClick event gives me an exception, saying I should be subscribing to the item click event, so I have done this using a clickable relative layout that surrounds the GridView (and its accompanying empty image view) as such:
...
<RelativeLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="#+id/addContactsRelativeLayout"
android:clickable="true">
<ImageView
android:id="#+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/ic_add" />
<Mvx.MvxGridView
android:id="#+id/addContactsGridView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:MvxBind="ItemsSource Contacts"
local:MvxItemTemplate="#layout/contact_summary_item"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:columnWidth="55dip"
android:gravity="center" />
</RelativeLayout>
...
This works fine when the GridView is empty, and the empty ImageView is shown. However, when there are items in the GridView, the RelativeLayout no longer seems to exist and clicks over the GridView can be seen to highlight items on the GridView. This means the user is not taken to the screen to edit their contact list.
I have tried several different configurations and attributes from similar questions on SO, but I think the addition of an empty view is causing problems. Any help would be greatly appreciated.
Ok, after a lot more playing around I found a solution.
Essentially it's adding another relative layout, higher in the z-index and therefore above the 'real' contents, within the surrounding relative layout.
...
<RelativeLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<ImageView
android:id="#+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="#drawable/ic_add" />
<Mvx.MvxGridView
android:id="#+id/addContactsGridView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:MvxBind="ItemsSource Contacts"
local:MvxItemTemplate="#layout/contact_summary_item"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:columnWidth="55dip"
android:gravity="center"
android:focusable="false"/>
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:clickable="true"
android:id="#+id/addContactsRelativeLayout"/>
...
Then just move all your click listeners to listen to the relative layout at the bottom.

Make same space between buttons in a HorizontalScrollView

This is a solution in order to add same space between views in the layout:
make same space between button in linearlayout
But let say we have many items and we need to put them in HorizontalScrollView for handset devices.
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<LinearLayout
android:id="#+id/shareLinearLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/btnRequestAPrescriptionRefill"
android:layout_marginTop="10dp" >
<Button
android:id="#+id/btnFacebook"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/btn_facebook" />
<View
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1" />
...
</LinearLayout>
</HorizontalScrollView>
This solution works fine for handsets but in the tablet where we have a big screen size, the same space between buttons is not working. Buttons are just sticking together without no space that we created by:
<View
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1" />
Is there any solution?
A scroll view adapts it's size to its content view (the linear layout) but when the screen is large enough you want it the other way around, you want the content view to adapt its size to the scroll view. This is a little contradictory.
The only way to do this is specifying a minWidth property for your LinearLayout.
android:minWidth="200dp"
This is a pain in the butt because you probably need to set it at runtime, or have many versions of your XML for different screen resolutions.
Maybe another approach for large screen resolutions would be providing a different XML without the scrollview.

Resources