dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.28k stars 1.76k forks source link

Scrolling of Editor placed in ScollView does not work. #13634

Open cat0363 opened 1 year ago

cat0363 commented 1 year ago

Description

Provide a mechanism for users to control what control captures touch when the user is trying to scroll inside a nested control

Workaround

https://github.com/dotnet/maui/pull/24531#issuecomment-2374724124

Notes

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. ```xaml ``` 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](https://github.com/dotnet/maui/issues/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. ```cs 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(); 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.
ghost commented 1 year ago

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.

cat0363 commented 1 year ago

I have uploaded the code for this issue to github. https://github.com/cat0363/Maui-Issue13634

ghost commented 1 year ago

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.

hector2d2 commented 1 year ago

Is the same problem with ios.

cat0363 commented 1 year ago

Hi, @hector2d2 I didn't have an iOS build environment ready yet, so thanks for investigating.

cat0363 commented 1 year ago

I also confirmed that this issue occurs on iOS as well. .NET MAUI 7.0 (Current) iOS 16.4

Zhanglirong-Winnie commented 1 year ago

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 13634

OudomMunint commented 1 year ago

Having the same issue. With .Net 7 on iOS only

SamuelJames101 commented 6 months ago

I am still seeing this issue in Maui

maonaoda commented 4 months ago

I am still seeing this issue in Maui

breenbob commented 3 months ago

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

PureWeen commented 2 months ago

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

LaraSQP commented 1 month ago

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.

breenbob commented 1 month ago

@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 commented 1 month ago

@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.