maui
maui copied to clipboard
Scrolling of Editor placed in ScollView does not work.
If this issue is related to #9827, is there a specific solution? This Issue also occurred in Xamarin.Forms, but continues to occur in .NET MAUI.
Discussed in https://github.com/dotnet/maui/discussions/13632
Originally posted by cat0363 March 2, 2023 To reproduce, layout as follows.
<ScrollView Orientation="Vertical">
<Grid RowDefinitions="100,100,100,100,*,100">
<Grid Grid.Row="0" BackgroundColor="Red" />
<Grid Grid.Row="1" BackgroundColor="Yellow" />
<Grid Grid.Row="2" BackgroundColor="Green" />
<Grid Grid.Row="3" BackgroundColor="Blue" />
<Editor Grid.Row="4" x:Name="txtTest" HeightRequest="150" WidthRequest="250"
VerticalOptions="Start" HorizontalOptions="Start"
Text="1
2
3
4
5
6
7
8
9
10" />
<Grid Grid.Row="5" BackgroundColor="Purple" />
</Grid>
</ScrollView>
Code: https://github.com/cat0363/Maui-Issue13634
Assume that the Editor has enough Text to scroll. If you scroll vertically on the editor after scrolling to the editor, scrolling on the editor side will not work. Similar to when the Map is placed inside a ScrollView (#13628), It seems that the tap event is being handled by the Editor's parent control, ScrollView.
Since the build environment has not been prepared, it cannot be confirmed for iOS, but at least it is as described for Android.
https://user-images.githubusercontent.com/125236133/222359185-639224e3-5ead-4883-8f69-feecea7f079d.mp4
The only solution I found is below.
public override bool DispatchTouchEvent(MotionEvent e)
{
if (e.Action == MotionEventActions.Down ||
e.Action == MotionEventActions.Move ||
e.Action == MotionEventActions.Up)
{
// Search EditText Control
var editors = (Window.DecorView as ViewGroup).GetChildrenOfType<EditText>();
foreach (var editor in editors)
{
// Initialize EditText screen position
int[] pos = new int[2];
// Set EditText screen position
editor.GetLocationOnScreen(pos);
// Create hit test rectangle
Rect hitRect = new Rect(pos[0], pos[1], editor.Width, editor.Height);
// Judge hit test
bool isHitTest = hitRect.Contains(e.GetX(), e.GetY());
// Hit test result is OK
if (isHitTest)
{
// Touch event intercept
editor.Parent.RequestDisallowInterceptTouchEvent(true);
}
}
}
return base.DispatchTouchEvent(e);
}
In the MainActivity.cs file, re-implement DispatchTouchEvent, get the EditText that exists in the page, execute the hit test, and if it is a EditText, intercept the touch event. Alternatively, you can reimplement the EditText's TouchListener in your EditorHandler to intercept touch events.
https://user-images.githubusercontent.com/125236133/222359497-c32f6388-dd6a-429c-bb92-a5dbd75232a3.mp4
Any other good ideas? I have not confirmed how it works on iOS, so I would like to know if there is no problem with iOS. Thank you.
Hi @cat0363. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md
This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
I have uploaded the code for this issue to github. https://github.com/cat0363/Maui-Issue13634
We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.
Is the same problem with ios.
Hi, @hector2d2 I didn't have an iOS build environment ready yet, so thanks for investigating.
I also confirmed that this issue occurs on iOS as well. .NET MAUI 7.0 (Current) iOS 16.4
Verified this issue with Visual Studio Enterprise 17.7.0 Preview 2.0. Can repro on android platform with sample project.
Maui-Issue13634-main.zip
Having the same issue. With .Net 7 on iOS only
I am still seeing this issue in Maui
I am still seeing this issue in Maui
I've hit same issue. I went with the Handler based alternative workaround, which worked well:
Anywhere in /Platforms/Android folder:
public class EditorScrollTouchListener : Java.Lang.Object, View.IOnTouchListener
{
public bool OnTouch(View? v, MotionEvent? e)
{
if (v is AppCompatEditText editText)
{
if (IsTextScrollable(editText))
{
// It is not sufficient to just return false from OnTouch
// you must request this from the parent control also
editText.Parent?.RequestDisallowInterceptTouchEvent(true);
}
}
return false;
}
private bool IsTextScrollable(EditText editText)
{
int textHeight = editText.Layout?.Height ?? 0;
int visibleHeight = editText.Height - editText.PaddingTop - editText.PaddingBottom;
return textHeight > visibleHeight;
}
}
On startup in MauiProgram.cs:
Microsoft.Maui.Handlers.EditorHandler.Mapper.AppendToMapping("EnableVerticalScroll", (handler, view) =>
{
#if ANDROID
handler.PlatformView.VerticalScrollBarEnabled = true;
handler.PlatformView.SetOnTouchListener(new EditorScrollTouchListener());
#endif
});
Thanks for sharing @cat0363
I've added some notes here
https://github.com/dotnet/maui/pull/24531#issuecomment-2374724124
This isn't inherently a bug
Ideally here we wouldn't just change the behavior for Android users as that might frustrate some set of users. The approach here would be to add some mechanism to allow developers to control how touch behavior is captured when the user scrolls
I've hit same issue. I went with the Handler based alternative workaround, which worked well:
Anywhere in /Platforms/Android folder:
public class EditorScrollTouchListener : Java.Lang.Object, View.IOnTouchListener { public bool OnTouch(View? v, MotionEvent? e) { if (v is AppCompatEditText editText) { if (IsTextScrollable(editText)) { // It is not sufficient to just return false from OnTouch // you must request this from the parent control also editText.Parent?.RequestDisallowInterceptTouchEvent(true); } } return false; } private bool IsTextScrollable(EditText editText) { int textHeight = editText.Layout?.Height ?? 0; int visibleHeight = editText.Height - editText.PaddingTop - editText.PaddingBottom; return textHeight > visibleHeight; } }
Can you share the entire file for EditorScrollTouchListener. Various elements cannot be resolved (like View.IOnTouchListener or AppCompatEditText) due to missing usings that cannot be found or are incompatible.
Much appreciated.
@LaraSQP all that is missing is the using statements:
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.Widget;
using View = Android.Views.View;
Hope this helps.
@LaraSQP all that is missing is the using statements:
using Android.Views; using Android.Widget; using AndroidX.AppCompat.Widget; using View = Android.Views.View;Hope this helps.
Much appreciated. You rock.
For now, an improved version of the touch listener for Editor that allows parent scrolling when the editor's content is already at the top or bottom, preventing unnecessary blocking of scroll gestures, until the official fix is released.
Anywhere in /Platforms/Android folder:
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.Widget;
using View = Android.Views.View;
namespace YourNamespace.Platforms.Android
{
public class EditorScrollTouchListener : Java.Lang.Object, View.IOnTouchListener
{
private float? _lastY;
public bool OnTouch(View? v, MotionEvent? e)
{
if (v is not AppCompatEditText editText || e == null)
return false;
switch (e.Action)
{
case MotionEventActions.Down:
_lastY = e.GetY();
editText.Parent?.RequestDisallowInterceptTouchEvent(true);
break;
case MotionEventActions.Move:
if (!_lastY.HasValue)
{
_lastY = e.GetY();
return false;
}
float deltaY = e.GetY() - _lastY.Value;
_lastY = e.GetY();
bool isScrollable = IsTextScrollable(editText);
bool atTop = editText.ScrollY <= 0;
bool atBottom = editText.ScrollY >= GetMaxScroll(editText);
editText.Parent?.RequestDisallowInterceptTouchEvent(isScrollable && !(deltaY > 0 && atTop || deltaY < 0 && atBottom));
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
_lastY = null;
editText.Parent?.RequestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
private int GetMaxScroll(EditText editText) => (editText.Layout?.Height ?? 0) - editText.Height + editText.PaddingTop + editText.PaddingBottom;
private bool IsTextScrollable(EditText editText) => (editText.Layout?.Height ?? 0) > editText.Height - editText.PaddingTop - editText.PaddingBottom;
}
}
CreateMauiApp in MauiProgram.cs.
Microsoft.Maui.Handlers.EditorHandler.Mapper.AppendToMapping("EnableVerticalScroll", (handler, view) =>
{
#if ANDROID
handler.PlatformView.VerticalScrollBarEnabled = true;
handler.PlatformView.SetOnTouchListener(new YourNamespace.Platforms.Android.EditorScrollTouchListener());
#endif
});