使 WebView 的列表可滚动
Make WebView's list scrollable
我有一个看起来像这样的页面*:
<ScrollView>
<WebView/>
<WebView/>
<WebView/>
</Scrollview>
* 不是实际布局,但它足以解决问题并使问题更清楚。
我不知道 WebView
到底是什么样子,因为它可能变化很大。 WebView
可以包含可滚动列表。
我想实现这种滚动行为:
这是两个 WebView(蓝色 header 和绿色 header 的一个)。我只想在列表中拖动时以蓝色 WebView
滚动列表。如果我触摸其他任何地方(例如蓝色或绿色 header),我想在 ScrollView
.
中滚动
我尝试解决这个问题是 WebView
的 CustomRenderer
,我在 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
中滚动13=].
所以我尝试检查内部列表的高度:
case MotionEventActions.Down:
if (ComputeVerticalScrollRange() > MeasuredHeight)
Control.Parent.RequestDisallowInterceptTouchEvent(true);
break;
case MotionEventActions.Up:
if (ComputeVerticalScrollRange() > MeasuredHeight)
Control.Parent.RequestDisallowInterceptTouchEvent(false);
break;
MeasuredHeight
是WebView
的高度。 ComputeVerticalScrollRange()
将始终 return 与 MeasuredHeight
相同的高度。因此,一种可能的解决方案是获取 WebView
中内部列表的高度,但我不知道如何获取(我是 Android 的新手)。也许,甚至还有其他解决方案。
对于代码 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
到达顶部并且从上到下滚动时禁用滚动,反之亦然。你可以试试。
我有一个看起来像这样的页面*:
<ScrollView>
<WebView/>
<WebView/>
<WebView/>
</Scrollview>
* 不是实际布局,但它足以解决问题并使问题更清楚。
我不知道 WebView
到底是什么样子,因为它可能变化很大。 WebView
可以包含可滚动列表。
我想实现这种滚动行为:
这是两个 WebView(蓝色 header 和绿色 header 的一个)。我只想在列表中拖动时以蓝色 WebView
滚动列表。如果我触摸其他任何地方(例如蓝色或绿色 header),我想在 ScrollView
.
我尝试解决这个问题是 WebView
的 CustomRenderer
,我在 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
中滚动13=].
所以我尝试检查内部列表的高度:
case MotionEventActions.Down:
if (ComputeVerticalScrollRange() > MeasuredHeight)
Control.Parent.RequestDisallowInterceptTouchEvent(true);
break;
case MotionEventActions.Up:
if (ComputeVerticalScrollRange() > MeasuredHeight)
Control.Parent.RequestDisallowInterceptTouchEvent(false);
break;
MeasuredHeight
是WebView
的高度。 ComputeVerticalScrollRange()
将始终 return 与 MeasuredHeight
相同的高度。因此,一种可能的解决方案是获取 WebView
中内部列表的高度,但我不知道如何获取(我是 Android 的新手)。也许,甚至还有其他解决方案。
对于代码 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
到达顶部并且从上到下滚动时禁用滚动,反之亦然。你可以试试。