具有RecycleView,它具有一些项目,其中之一是包含WebView的视图。在WebView内加载一个html,并且有一个内嵌框架,该内嵌框架具有html表内容,并且可垂直滚动(包含div的固定高度小于表的高度)。
RecyclerView似乎存在问题,即它没有将触摸事件传递给WebView。
这会发生什么:
触摸屏幕以进行拖动时,recycleView的onInterceptTouchEvent()首先return false at ACTION_DOWN
,然后return true when the event is MotionEvent.ACTION_MOVE
。此return true
将发送MotionEvent.Cancel到目标子视图,以及所有其他信息
事件将传递到RecycleView的onTouchEvent()
TestDerivedRecycleView:onInterceptTouchEvent(), return: false
event: MotionEvent { action=ACTION_DOWN, actionButton=0... }, this.scrollState: 0
TestDerivedRecycleView:onInterceptTouchEvent(), return: true
event: MotionEvent { action=ACTION_MOVE, actionButton=0... }, this.scrollState: 1
因此,我创建了一个派生的RecycleView,当目标视图上的事件为ACTION_MOVE时,则为WebView,然后为return false to let WebView handle the drag/move
。
部分正常。由于webView可能具有其他一些内容,例如文本区域。如果触摸该文本区域,则该文本区域不可滚动,因此回收视图将不会滚动。仅当触摸并拖动该表格元素时,表格元素才会滚动表格内容。
所需的行为应该是在RecyclerView上拖动任何项目时,RecyclerView应该向上滚动项目,仅当在该可滚动表格元素上拖动时,如果未显示表格底部,表格才应滚动其内容。
当Webview是RecycleView的子项时,如何使Webview的内容滚动工作?
class TestDerivedRecycleView : RecyclerView {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
override fun onTouchEvent(event: MotionEvent): Boolean {
val ret = super.onTouchEvent(event)
Log.d("+++", "+++ TestDerivedRecycleView:onTouchEvent(), ret: $ret" +
"\nevent.action: ${event.action}, " +
"\nevent: $event" +
"\nthis: ${this}")
return ret
}
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
val ret = super.onInterceptTouchEvent(event)
val myCell = findChildViewUnder(event.x, event.y)
Log.w("+++", "+++ TestDerivedRecycleView:onInterceptTouchEvent(), ret: $ret" +
"\nmyCell: $myCell"+
"\n event.action: ${event.action}, this.scrollState: ${this.scrollState}" +
"\nevent: $event"+
"\nthis: $this")
// when the event is ACTION_MOVE and is touched on the WebView then return false to let WebView handle the event
if (
(myCell is ArticleWebView) &&
event.action == MotionEvent.ACTION_MOVE
&& this.scrollState == RecyclerView.SCROLL_STATE_DRAGGING
) {
Log.e("+++", "+++ TestDerivedRecycleView:onInterceptTouchEvent(), (myCell is WebView) return false")
return false
}
return ret
}
}
答案 0 :(得分:0)
找到解决方案,但不知道。
基本上,问题是RecycleView截获了'move'事件(其super.onInterceptTouchEvent(event)
将返回true),因此Webview将收到一个'cancel'事件,并且没有其他后续事件,这使得该项目在RecyclerView中滚动,但webview没有机会滚动其内容。
解决方案是不允许RecyclerView拦截“移动”事件。
此方法还有另一个问题,因为在WebView中html可能具有一些可滚动的内容和一些不可滚动的内容。如果简单地让webview接管移动并且触摸点位于某个不可滚动的区域,则触摸/拖动移动将不起作用(RecyclerView中的项目项也不会滚动,因为它不再拦截事件了)
因此,此部分解决方法是仅当在Webview上用两根手指触摸然后禁用RecyclerView的拦截器时。这样,至少单指触摸将继续滚动列表项,而两指触摸将滚动webview的可滚动内容。
最糟糕的是两根手指触摸一个webview的不可滚动区域将不会产生滚动效果。
如果有人知道更好的解决方案,请分享,谢谢!
在Webview中添加了侦听器:
val listener = OnTouchListener { v, event ->
var perantViewGroup = v.parent
when {
event.actionMasked == MotionEvent.ACTION_DOWN -> mFingersDown = 1
event.actionMasked == MotionEvent.ACTION_POINTER_DOWN -> mFingersDown++
event.actionMasked == MotionEvent.ACTION_POINTER_UP -> mFingersDown--
event.actionMasked == MotionEvent.ACTION_UP -> mFingersDown = 0
}
if ((mFingersDown >= 2) && event.actionMasked == MotionEvent.ACTION_MOVE) {
perantViewGroup.requestDisallowInterceptTouchEvent(true)
} else if (event.actionMasked == MotionEvent.ACTION_UP) {
perantViewGroup.requestDisallowInterceptTouchEvent(false)
}
false
}
webview.setOnTouchListener(listener)
,并且还在RecycleView中添加了一些帮助以防止其拦截“移动”事件。
class TestDerivedRecycleView : RecyclerView {
......
private var mFingersDown = 0
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
when {
event.actionMasked == MotionEvent.ACTION_DOWN -> mFingersDown = 1
event.actionMasked == MotionEvent.ACTION_POINTER_DOWN -> mFingersDown++
event.actionMasked == MotionEvent.ACTION_POINTER_UP -> mFingersDown--
event.actionMasked == MotionEvent.ACTION_UP -> mFingersDown = 0
}
val touchedCell = findChildViewUnder(event.x, event.y)
if ((touchedCell is WebView) && (mFingersDown >= 2) && event.actionMasked == MotionEvent.ACTION_MOVE) {
return false
}
return super.onInterceptTouchEvent(event)
}
}
答案 1 :(得分:0)
我遇到了同样的问题,并以此解决了-
在您的WebView
类中:
@Override
public boolean onTouchEvent(MotionEvent event) {
requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(event);
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
if(scrollY==0){
requestDisallowInterceptTouchEvent(false);
}else{
requestDisallowInterceptTouchEvent(true);
}
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}