如何滚动加载到Webview中的可滚动内容,这是RecycleView的一项

时间:2018-12-03 22:24:53

标签: scroll android-recyclerview android-webview ontouchevent

具有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
    }
}

2 个答案:

答案 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);

}