WebView无法正确加载

时间:2014-06-21 17:25:51

标签: android html android-layout scroll android-webview

我有一个应用程序可以在三个WebViews中加载HTML内容。为简单起见,我们将它们称为顶部,中部和底部。

用户始终在查看中间WebView。当用户到达页面顶部并向下滑动时,三个WebView的布局会发生变化,以便顶视图可见。相反,当用户到达页面底部并向上滑动时,底部页面就会显示出来。

想象一下100x100的屏幕。坐标0,0是屏幕的左上角,100,100是屏幕的右下角。顶部视图将具有顶部为-105的布局,因此它不可见,中间视图将占据屏幕,底部视图将具有顶部为105的布局,因此它也是不可见的

topLayout.topMargin = -105;
middleLayout.topMargin = 0;
bottomLayout.topMargin = 105;

top.setLayoutParams(topLayout);
middle.setLayoutParams(middleLayout);
bottom.setLayoutParams(bottomLayout);

内容是书籍,因此当用户更改页面时,内容应该在逻辑上流动。向后(向上)滚动时,应显示上一页的底部。向前(向下)滚动时,应显示下一页的顶部。这是通过使用scrollTo(x,y)设置WebView的滚动位置来完成的。代码如下所示,其中a代表内容的底部,b代表内容的顶部:

top.scrollTo(0, a);
middle.scrollTo(0, {a,b}); // a for previous page; b for next page
bottom.scrollTo(0, b);

当用户滑动到上一页时,顶部WebView的布局会更改为顶部为0以占据屏幕;中间变为105,底部变为-105并加载不同的内容,以便应用程序为将来的滑动做好准备。  

<小时/> 现在我们真的回答了我的问题。除了Android 4.4(KitKat)之外,这完全符合预期。在KitKat中,它适用于任一方向的两次滑动,但随后在第三次和随后的滑动方向相同,内容将加载到错误的位置。向后滚动时,内容开始加载显示顶部。向前滚动时,内容开始加载显示底部。

我已经通过调试器并注意到布局设置正确,然后正确设置了滚动位置。然后,在设置这些值之后,但在实际绘制内容之前,堆栈中会发生一些更改滚动位置的事件。

这是我完全迷失的地方。为什么滚动值设置正确,然后在绘制屏幕之前神奇地改变?

我已经尝试使用onLayoutCompleteListener,但它没有用。我将在收到答案时更新所尝试的事项列表并尝试建议。提前感谢您提供任何帮助。


以下是我正在做的更改网页的摘要:

public class MyWebView extends WebView {

    // Assume this is instantiated; it is by the time it is needed
    private List<MyWebView> viewArray = new List<MyWebView>(3); 

    private class CustomGestureListener extends 
        GestureDetector.SimpleOnGestureListener {

        private static final String DEBUG_TAG = "Gestures";
        private int scrollYOnTouch;
        private int scrollYOnRelease;

        @Override
        public boolean onFling(MotionEvent event1, MotionEvent event2, 
                float velocityX, float velocityY) {
            Log.d(DEBUG_TAG, "onFling: " + event1.toString() 
                + event2.toString());
            Log.i(DEBUG_TAG, "onFling: vX[" + velocityX 
                + "], vY[" + velocityY + "]");

            scrollYOnRelease = getScrollY();
            int bottomOfPage = scrollYOnTouch + getMeasuredHeight();
            int endOfContent = (int) Math.floor(getContentHeight() * getScale());
            int proximity = endOfContent - bottomOfPage;
            boolean atBottom = proximity <= 1;
            Log.i(DEBUG_TAG, "atBottom = (" + proximity + " <= 1)");

            if ((velocityY > VELOCITY_THRESHOLD) 
                && (scrollYOnRelease <= 0) && (scrollYOnTouch == 0)) {
                // User flung down while at the top of the page.
                // Go to the previous page.
                changePages(PREVIOUS_PAGE);
            } else if ((velocityY < -VELOCITY_THRESHOLD) 
                && (scrollYOnRelease >= scrollYOnTouch) && atBottom) {
                // User flung up while at the bottom of the page.
                // Go to the next page.
                changePages(NEXT_PAGE);
            }
            return true;
        }
    } // end of CustomGestureListener

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Send the event to our gesture detector
        // If it is implemented, there will be a return value
        this.mDetector.onTouchEvent(event);
        // If the detected gesture is unimplemented, send it to the superclass
        return super.onTouchEvent(event);
    }

    @Override
    public void changePages(int direction) {

        int screenWidth = getScreenWidth();
        int screenHeight = getScreenHeight();

        VerticalPagingWebView previous;
        VerticalPagingWebView current;
        VerticalPagingWebView next;

        if (direction == NEXT_PAGE) {
            // Rearrange elements in webview array
            // Next page becomes current page,
            // current becomes previous,
            // previous becomes next.
            Collections.swap(viewArray, 0, 1);
            Collections.swap(viewArray, 1, 2);

            previous = viewArray.get(0);
            current = viewArray.get(1);
            next = viewArray.get(2);

            // Prepare the next page
            next.loadData(htmlContent, "text/html", null);

        } else if (direction == PREVIOUS_PAGE) {
            // Rearrange elements in webview array
            // Previous page becomes current page,
            // current becomes next,
            // next becomes previous.
            Collections.swap(viewArray, 1, 2);
            Collections.swap(viewArray, 0, 1);

            previous = viewArray.get(0);
            current = viewArray.get(1);
            next = viewArray.get(2);

            // Prepare the previous page
            previous.loadData(htmlContent, "text/html", null);
        }

        LayoutParams previousLayout = (LayoutParams) previous.getLayoutParams();
        previousLayout.leftMargin = LEFT_MARGIN;
        previousLayout.topMargin = -screenHeight - TOP_MARGIN;
        previous.setLayoutParams(previousLayout);

        LayoutParams currentLayout = (LayoutParams) current.getLayoutParams();
        currentLayout.leftMargin = LEFT_MARGIN;
        currentLayout.topMargin = 0;
        current.setLayoutParams(currentLayout);

        LayoutParams nextLayout = (LayoutParams) next.getLayoutParams();
        nextLayout.leftMargin = LEFT_MARGIN;
        nextLayout.topMargin = screenHeight + TOP_MARGIN;
        next.setLayoutParams(nextLayout);

        previous.scrollToBottom();
        next.scrollToTop();

        // I'm unsure if this is needed, but it works on everything but KitKat
        if (direction == NEXT_PAGE) {
            current.scrollToTop();
        } else {
            current.scrollToBottom();
        }
    } // end of changePages

    public void scrollToPageStart() {
        scrollTo(0,0);
    }

    public void scrollToPageBottom() { 
        // I know getScale() is deprecated; I take care of it.
        // This method works fine.
        int endOfContent = (int) Math.floor(getContentHeight() * getScale());
        int webViewHeight = getMeasuredHeight();
        scrollTo(0, endOfContent - webViewHeight);
    }
}

1 个答案:

答案 0 :(得分:1)

您可能在完成加载内容之前滚动WebView。问题是,在页面加载期间的某个时刻,WebView会重置滚动(这是有意的,当您在页面之间导航时,您不希望滚动偏移持续存在),有时在您调用{{1 }}

要解决此问题,您有两种选择:

  1. 从JavaScript滚动(在window.onload或其他东西中),这可确保在WebView加载完内容后进行滚动,
  2. 在滚动之前等待内容加载。这很难,因为WebView没有可靠的回调(scrollTo无法可靠地工作)。一种选择是在进行滚动之前轮询onPageFinished方法何时返回内容的高度。