Bug 59933 - RelativeLayout with InputTransparent = true occluding RelativeLayout beneath
Summary: RelativeLayout with InputTransparent = true occluding RelativeLayout beneath
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.4.0
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: ---
Assignee: E.Z. Hart [MSFT]
Depends on:
Reported: 2017-10-03 18:06 UTC by Daniel Robbins
Modified: 2017-10-08 23:37 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

Working version of sample code (297.34 KB, application/x-zip-compressed)
2017-10-06 20:12 UTC, E.Z. Hart [MSFT]

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Daniel Robbins 2017-10-03 18:06:24 UTC
I am using Xamarin Forms 

I am using a technique where I have two RelativeLayouts that are part of a Grid -- in fact, they have been added to the same part of the grid. One, the lower RelativeLayout (slidein_layout) is offset, out of the visible area so it cannot be seen, and scrolls in from off-screen for a dynamic effect, while the other (static_layout) contains elements that do not move. Both RelativeLayouts contain children that receive input. In my case, I have Tap Gesture Recognizer in bottom right corner of the top RelativeLayout, and I have Entry and Picker elements in the RelativeLayout beneath. I have used RelativeLayout functionality so that after slidein_layout has transitioned to its final location, input elements from both RelativeLayouts are visible and not overlapping one another. 

The issue I experience is that the top RelativeLayout (static_layout) will receive all input events, and nothing in the lower RelativeLayout (slidein_layout) will at all. This is true *even if* I set InputTransparent = true on the top RelativeLayout. So the entire area of the top RelativeLayout occludes the bottom RelativeLayout from any input.

While the behavior of InputTransparent is not entirely clear to me, I would expect one of two behaviors, which to me would make sense:

1) Setting InputTransparent on the top RelativeLayout would allow it to pass input events to the RelativeLayout (and its children) below, *if* one of its own children did not handle the Input event itself. This would be my preferred behavior.

2) Setting InputTransparent on the top RelativeLayout would apply to the top RelativeLayout *and all its children*, and any input would not be handled by the InputTransparent RelativeLayout but instead go to the RelativeLayout underneath. This would at least make sense, if one decided that InputTransparent, when applied to a Layout, also transitively applied to all its children. However, this would be far less flexible as it would not allow individual InputTransparent settings applied to the children, so #1 would be strongly preferred.

If neither #1 or #2 is the desired behavior of InputTransparent when applied to Layouts, then we at the very least need some clarification of how InputTransparent behaves in this scenario, and clarification to the documentation so that Forms users can easily understand what to expect when it comes to input occlusion.
Comment 1 Daniel Robbins 2017-10-03 18:20:13 UTC
To clarify, I am actually not moving the slidein_layout, which is integrated into an on-screen grid. It has a StackLayout within it that contains all elements, that is initially offset so it is not visible, and then TransitionTo is used to move the StackLayout and associated elements within the bounds of the parent RelativeLayout.

For the static_layout, this is a RelativeLayout and the child input element is a StackLayout that has been turned into an input element via a TapGestureRecognizer.

To me, the details of the slidein_layout in the first paragraph shouldn't matter too much, as the static_layout on top is simply occluding everything underneath even with InputTransparent = true set on the static_layout.
Comment 3 Daniel Robbins 2017-10-05 23:45:51 UTC
Yes, see here where I posted some sample code that is failing:

Comment 4 E.Z. Hart [MSFT] 2017-10-06 20:12:09 UTC
Created attachment 25179 [details]
Working version of sample code


I tried your code on previous versions of XF back to 1.5, and I can't find a version where it works. 

The main issue is that the Picker is initially laid out offscreen and then translated onto the screen; even after translating it onto the screen, the control's input layout remains off screen and the user can't interact with it. An alternative way to accomplish the effect you're aiming for is to initially lay out the control on screen, translate the control off screen, and then translate the control back to the on-screen position (i.e., calling .TranslateTo(0,0) when you want it animated onto the screen. At this point, the visible position of the control and its input layout will match, and the user can interact with it. 

I'm attaching a project with a slightly modified version of your code which uses this method to animate the control onto the screen.

You are correct that with the two overlapping RelativeLayouts, the top layout prevents the bottom layout from receiving input. And if the top layout is marked InputTransparent, it also makes the "Next" button InputTransparent, preventing it from being clicked. In the attached project I've worked around this by putting all of the controls in a single RelativeLayout.
Comment 5 Daniel Robbins 2017-10-06 21:09:58 UTC
I believe that I had a version that worked, the Forms upgrade broke it, and then I rewrote the version to use two RelativeLayouts as in the demo code, which apparently is never supposed to work.

Please consider adding some functionality to allow my code to work as-is or with very minor modifications. The current behavior is not intuitive. Users expect to be able to translate something and not have it break. They just want it to work.

In other words, by supporting arbitrary transitions of input elements, you will allow users to focus on the behavior of their app rather than the peculiarities of Xamarin Forms implementation.

Some ideas on how to gracefully address this -- a call that can be made to say 'Everything is in its final location'. This is straightforward. Users who translate input elements can then be instructed to make this call to tell Forms to update the position of the input elements so that re-aligning with their original location (what I consider a 'hack') is not necessary. This gives the programmer the ability to do translations as they see fit and not worry about shuffling everything back to its original location.

Another idea -- auto-update the layout of input elements after every TranslateTo call. Possibly slower but would eliminate to make the manual call at all.
Comment 6 Daniel Robbins 2017-10-08 23:37:44 UTC
Also, thanks very much for the fixed code. I do appreciate it. Please consider my request as a feature enhancement rather than a bug -- I doubt I will be the last who will encounter this particular quirk of Forms.