Горизонтальная прокрутка WebView Inside ViewPager

В этом вопросе было несколько вопросов , но никто не дал правильного решения, которое работает для нас. У нас есть ViewPager, содержащий динамическое количество веб-просмотров (внутри фрагментов), которые иногда нужно прокручивать по горизонтали.

Проблема, которую мы видим, заключается в том, что при прокрутке по горизонтали эти события прокрутки (или перетаскивание или переброски) перехватываются ViewPager, который затем вызывает переключатель страницы в направлении действия.

WebView либо не сообщает ширину своего содержимого своему родительскому объекту, либо ViewPager без разбора захватывает действия до того, как он должен.

Я попытался использовать решения computeHorizontalScroll(), которые казались многообещающими, но этот метод всегда возвращает 0 и не делает ничего хорошего.

  • Почему нет способа получить фактическую ширину содержимого содержимого WebView HTML, как есть getContentHeight()? Это даст нам то, что нам нужно, но, к сожалению, оно не предусмотрено в API.
  • Кто-нибудь видел обходной путь для этой проблемы, которая действительно работает?

Ответы

Ответ 1

Итак, я закончил разработку решения, запретив распространение сенсорных событий на ViewPager и прокрутку страниц при запуске события overScrollBy в WebView. Вы можете определить направление, в котором хотите прокручиваться, путем проверки дельта X события. Здесь kotlin решение:

override fun overScrollBy(deltaX: Int, deltaY: Int, scrollX: Int, scrollY: Int, scrollRangeX: Int, scrollRangeY: Int, maxOverScrollX: Int, maxOverScrollY: Int, isTouchEvent: Boolean): Boolean {
    if(parent.parent is WebViewPager) {
        val viewPager: WebViewPager = (parent.parent as WebViewPager)
        if(viewPager.scrollState == ViewPager.SCROLL_STATE_IDLE) {
            if(deltaX > 0) {
                if(checkAdapterLimits(1, viewPager.currentItem)) //right
                    (parent.parent as ViewPager).setCurrentItem(viewPager.currentItem + 1,true)
            }
            else {
                if(checkAdapterLimits(-1, viewPager.currentItem)) //left
                    (parent.parent as ViewPager).setCurrentItem(viewPager.currentItem - 1,true)
            }
        }
    }
    return false
}

override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
    parent.requestDisallowInterceptTouchEvent(true)

    return super.onInterceptTouchEvent(event)
}

private fun checkAdapterLimits(direction: Int, position: Int) : Boolean {
    return if(direction < 0) //left
        position >= 1
    else //right
        position < (parent.parent as ViewPager).adapter.count - 1

}

Отредактировано, чтобы остановить прокрутку только на одну страницу за раз, вам нужно проверить состояние прокрутки ViewPager, чтобы убедиться, что он не работает.

Вам нужно добавить свойство в свой собственный ViewPager и переключить его с помощью OnPageChangedListener на экземпляр ViewPager, который вы используете.

ViewPager:

class WebViewPager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {

var scrollState: Int = SCROLL_STATE_IDLE

fun setDurationScroll(millis: Int) {
    try {
        val viewpager = ViewPager::class.java
        val scroller = viewpager.getDeclaredField("mScroller")
        scroller.isAccessible = true
        scroller.set(this, OwnScroller(context, millis))
    } catch (e: Exception) {
        e.printStackTrace()
    }

}

inner class OwnScroller(context: Context, durationScroll: Int) : Scroller(context, DecelerateInterpolator()) {

    private var durationScrollMillis = 1

    init {
        this.durationScrollMillis = durationScroll
    }

    override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int, duration: Int) {
        super.startScroll(startX, startY, dx, dy, durationScrollMillis)
    }
}

}

OnPageChangedListener:

viewPager!!.setDurationScroll(300)
    viewPager!!.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {

        override fun onPageScrollStateChanged(state: Int) {
            viewPager.scrollState = state
        }

        override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {

        }
        override fun onPageSelected(position: Int) {

        }

    })

Ответ 2

ViewPager является родителем вашего WebView. Вы можете попытаться обнаружить движение салфетки в своем ViewPager и передать его непосредственно этому ребенку.

Вы можете проверить официальную документацию Управление событиями касания, и вы можете проверить this Обсуждение. Проверьте принятый ответ и, более конкретно, метод onInterceptTouchEvent().

Это может дать вам некоторые идеи.