使WebView的列表可滚动

时间:2017-09-12 13:26:02

标签: android xamarin.forms scrollview

我有一个看起来像这样的页面*:

<ScrollView>
  <WebView/>
  <WebView/>
  <WebView/>
</Scrollview>

*不是实际布局,但足以解决问题并使问题更加清晰。

我不知道WebView看起来到底是怎样的,因为它可能变化很大。 WebView 可以包含可滚动列表。

我想实现这种滚动行为:

enter image description here

这是两个WebView(带有蓝色标题的WebView和带有绿色标题的WebView)。我只想在列表中拖动时在蓝色WebView中滚动列表。如果我在其他地方触摸(例如在蓝色或绿色标题上),我想滚动ScrollView

我尝试解决这个问题的CustomRendererWebView,我在this thread in the Xamarin forums中找到了这个问题:

protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
    base.OnElementChanged(e);

    if (e.OldElement != null)
    {
        Control.Touch -= Control_Touch;
    }

    if (e.NewElement != null)
    {
        Control.Touch += Control_Touch;
    }
}

void Control_Touch(object sender, TouchEventArgs e)
{
    // Executing this will prevent the Scrolling to be intercepted by parent views
    switch (e.Event.Action)
    {
        case MotionEventActions.Down:
            Control.Parent.RequestDisallowInterceptTouchEvent(true);
            break;
        case MotionEventActions.Up:
            Control.Parent.RequestDisallowInterceptTouchEvent(false);
            break;
    }
    // Calling this will allow the scrolling event to be executed in the WebView
    Control.OnTouchEvent(e.Event);
}

这几乎完成了这项工作,我现在可以在WebView内的列表中滚动,但如果我点击ScrollView中的任何其他位置,它就不会再滚动WebView 1}}。

所以我试着检查内部列表的高度:

case MotionEventActions.Down:
    if (ComputeVerticalScrollRange() > MeasuredHeight)
        Control.Parent.RequestDisallowInterceptTouchEvent(true);
    break;
case MotionEventActions.Up:
    if (ComputeVerticalScrollRange() > MeasuredHeight)
        Control.Parent.RequestDisallowInterceptTouchEvent(false);
    break;

MeasuredHeightWebView的高度。 ComputeVerticalScrollRange()将始终返回与MeasuredHeight tho相同的高度。因此,一个可能的解决方案是在WebView中获取内部列表的高度,但我不知道如何得到它(我是Android的新手)。也许,甚至还有其他解决方案。

1 个答案:

答案 0 :(得分:1)

对于代码Control.Parent.RequestDisallowInterceptTouchEvent(true);,您需要确保此Control.Parent确实是ScrollViewer

AFAIK,为了实现每个平台的视图,它使用渲染器,Control.Parent这里是WebViewRenderer,所以我认为你需要的是这样的:

Control.Parent.Parent.Parent.Parent.RequestDisallowInterceptTouchEvent(true);

真正的问题是何时将其设置为true或false,您可以修改Control_Touch事件,例如:

private void Control_Touch(object sender, TouchEventArgs e)
{
    var viewheight = Control.MeasuredHeight;
    var height = (int)Math.Floor(Control.ContentHeight * Control.Scale);
    switch (e.Event.Action)
    {
        case MotionEventActions.Down:
            downY = e.Event.GetY();
            mAction = ActionState.None;
            Control.Parent.Parent.Parent.Parent.RequestDisallowInterceptTouchEvent(true);
            break;

        case MotionEventActions.Move:
            upY = e.Event.GetY();
            var delta = downY - upY;
            if (Math.Abs(delta) > MIN_DISTANCE)
            {
                if (delta < 0)
                {
                    mAction = ActionState.TB;
                    //top reached
                    if (Control.ScrollY == 0)
                    {
                        Control.Parent.Parent.Parent.Parent.RequestDisallowInterceptTouchEvent(false);
                    }
                }
                else if (delta > 0)
                {
                    mAction = ActionState.BT;

                    //bottom reached
                    if (Control.ScrollY + viewheight + 5 >= height)
                    {
                        Control.Parent.Parent.Parent.Parent.RequestDisallowInterceptTouchEvent(false);
                    }
                }
            }
            break;

        case MotionEventActions.Up:
            Control.Parent.Parent.Parent.Parent.RequestDisallowInterceptTouchEvent(true);
            break;
    }
    Control.OnTouchEvent(e.Event);
}

我使用了两个自定义WebView来测试我的演示,其目的是在WebView到达顶部并且从上到下滚动时禁用滚动,反之亦然。你可以尝试一下。