【问题标题】:render the epub book in android?在android中渲染epub书?
【发布时间】:2012-01-21 00:58:39
【问题描述】:

我正在尝试在 android pad 中显示 epub 书。我可以解析html和css,为了显示书的内容和格式,也许书里有图片,看来我有两个选择:

  1. 使用 Webview。
  2. 编写一个客户视图,以便它可以呈现 html/css --- 这似乎是一项非常复杂的任务。

什么是好方法?如果我必须使用WebView,那么分页逻辑怎么样,因为webview在一页中解析一个html文件,我在webview中找不到分页符。

【问题讨论】:

    标签: android webview render epub


    【解决方案1】:

    我为安卓和ios开发了一个原生的epub播放器

    我在这里分享的代码是我的产品源代码的一部分,复制和粘贴它对你不起作用。可以作为参考。

    我在android中使用过webview,在ios中使用uiwebview制作自定义视图和解析html/css几乎就像开发一个新的渲染引擎(即浏览器)。它是一个乏味和复杂的。

    简单地说,我给你我为 android 遵循的步骤

    • 创建自定义网页视图
    • 加载url和写回调客户端(WebViewClient,WebChromeClient)
    • webview 加载后使用以下方法进行分页

    代码:

    private class MyWebClient extends WebViewClient
        {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }
            @Override
            public void onPageFinished(WebView view, String url) 
            {
                super.onPageFinished(view, url);
    
                final MyWebView myWebView = (MyWebView) view;
    
                String varMySheet = "var mySheet = document.styleSheets[0];";
    
                    String addCSSRule = "function addCSSRule(selector, newRule) {"
                            + "ruleIndex = mySheet.cssRules.length;"
                            + "mySheet.insertRule(selector + '{' + newRule + ';}', ruleIndex);"
    
                            + "}";
    
                    String insertRule1 = "addCSSRule('html', 'padding: 0px; height: "
                            + (myWebView.getMeasuredHeight()/getContext().getResources().getDisplayMetrics().density )
                            + "px; -webkit-column-gap: 0px; -webkit-column-width: "
                            + myWebView.getMeasuredWidth() + "px;')";
    
                    myWebView.loadUrl("javascript:" + varMySheet);
                    myWebView.loadUrl("javascript:" + addCSSRule);
                    myWebView.loadUrl("javascript:" + insertRule1);
    
    
    
            }
        }
    
    private class MyWebChromeClient extends WebChromeClient
        {
            @Override
            public void onProgressChanged(WebView view, int newProgress) 
            {
                super.onProgressChanged(view, newProgress);
                //  GlobalConstants.ENABLE_WEB_VIEW_TOUCH = false;
                if(newProgress == 100)
                {
                    postDelayed(new Runnable() 
                    {
                        @Override
                        public void run() 
                        {
                            calculateNoOfPages();
    
                        }
                    },300);
                }
            }
        }
    
    private void calculateNoOfPages()
        {
    
            if(getMeasuredWidth() != 0)
            {
                int newPageCount = computeHorizontalScrollRange()/getMeasuredWidth();
            }
        }
    

    将 jquery.js 注入 webview:

    private void addJQueryJS() 
        {
            String path = "file:///android_asset/JSLibraries/jquery.min.js";
            String data = "{\"MethodName\":\"onJQueryJSLoaded\",\"MethodArguments\":{}}";
            String callBackToNative  = " jsInterface.callNativeMethod('jstoobjc:"+data+"');";
            String script = "function includeJSFile()"
                                   +"{"
                                   +"function loadScript(url, callback)"
                                   +"{"
                                   +"var script = document.createElement('script');"
                                   +"script.type = 'text/javascript';"
                                   +"script.onload = function () {"
                                   +"callback();"
                                   +"};"
                                   +"script.src = url;"
                                   +"if(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0])"
                                   +"{"
                                   +"(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);"
                                   +"}"
                                   +"else { callback(); }"
                                   +"}"
                                   +"loadScript('"+path+"', function ()"
                                   +"{"
                                   +callBackToNative
                                   +"});"
                                   +"} ; includeJSFile();";
            loadUrl("javascript: "+script);
        }
    
    • 将所有单词包装成 span - 用于突出显示文本和导航到页面。
    • 将有 3 个 webviews - 当前页、下一页和上一页。您应该根据该章节的页数设置 webview 滚动的偏移量。 假设一个 .html 文件的内容为 3 页 - 上一个 webview 是第一页,当前 webview 是第二页,下一个 webview 是第三页,但所有 webview 加载相同的 url。但它们的内容偏移量不同。
    • 编写您自己的页面滑动逻辑而不是使用 viewpager。只需将当前页面传递给适配器,然后适配器将返回下一页和上一页。通过一些计算。

    代码:

    @Override
        public PageView getPreviousView(PageView oldPage) 
        {
            MyWebView oldWebView = ((PageView)oldPage).getWebView();
    
            int chapterIndex = oldWebView.getData().getIndexOfChapter();
            int pageIndex = oldWebView.getData().getIndexOfPage();
            int pageCount = oldWebView.getData().getChapterVO().getPageCount();
            pageIndex--;
            if(pageIndex < 0)
            {
                pageIndex = 0;
                chapterIndex--;
                if(chapterIndex<0)
                {
                    //return the same page
                    chapterIndex = 0;
                    return null;
                }
                else
                {
                    //previous chapter last page
                    PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                    MyWebView webView= pageView.getWebView();
    
                    PageVO data = new PageVO();
                    data.setChapterVO(_chaptersColl.get(chapterIndex));
                    data.setIndexOfChapter(chapterIndex);
                    data.setIndexOfPage(-2);
    
                    webView.setData(data);
                    return pageView;
                }
            }
            else if(pageIndex <= pageCount-1)
            {
                //same chapter previous page
                PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                MyWebView webView= pageView.getWebView();
    
                PageVO data = new PageVO();
                data.setChapterVO(_chaptersColl.get(chapterIndex));
                data.setIndexOfChapter(chapterIndex);
                data.setIndexOfPage(pageIndex);
    
                webView.setData(data);
                return pageView;
            }
            return oldPage;
        }
    
        @Override
        public PageView getNextView(PageView oldPage) 
        {
            MyWebView oldWebView = ((PageView)oldPage).getWebView();
            int chapterIndex = oldWebView.getData().getIndexOfChapter();
            int pageIndex = oldWebView.getData().getIndexOfPage();
            int pageCount = oldWebView.getData().getChapterVO().getPageCount();
            pageIndex++;
            if(pageIndex>=pageCount)
            {
                pageIndex=0;
                chapterIndex++;
                if(chapterIndex>=_chaptersColl.size())
                {
                    //end of the chapters and pages so return the same page
                    chapterIndex--;
                    return null;
                }
                else
                {
                    //next chapter first page
                    PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                    MyWebView webView= pageView.getWebView();
    
                    PageVO data = new PageVO();
                    data.setChapterVO(_chaptersColl.get(chapterIndex));
                    data.setIndexOfChapter(chapterIndex);
                    data.setIndexOfPage(pageIndex);
    
                    webView.setData(data);
    
                    return pageView;
                }
            }
            else
            {
                //next page in same chapter
                PageView pageView = new PageView(oldPage.getContext(),_mViewPager);
                MyWebView webView= pageView.getWebView();
    
                PageVO data = new PageVO();
                data.setChapterVO(_chaptersColl.get(chapterIndex));
                data.setIndexOfChapter(chapterIndex);
                data.setIndexOfPage(pageIndex);
                //data.setPageCount(pageCount);
    
                webView.setData(data);
    
                return pageView;
            }
        }
    

    无需使用任何第三方库。只需花费大量时间编写自己的所有内容。

    【讨论】:

    • #Uday Sravan,我是 android 上的 epub 开发新手,在过去的 3 周里,我一直在尝试 Android ePub 分页和页面转换的几种选项。只有您的答案似乎可以正常工作。我可以让一些示例代码工作吗?
    • 你能告诉我,我应该什么时候调用 addJQueryJS() ?是在将 HTML 页面加载到 webview 之后还是之前?
    【解决方案2】:

    不错,但有问题... :-)

    我认为没有任何适用于 android webview 的分页逻辑可用,根据您的关注,WebView 是显示 .epub 文件的好选择(您可以添加许多功能,例如突出显示、搜索、书签等)。如果你找到了那个,那么如果设备大小改变了怎么办。我正在做的是,我只是在 webview 中显示 WebPage 并禁用滚动,然后我可以找到 webview 的最大高度和设备屏幕尺寸(高度和宽度),现在我已经为下一页和上一页放置了两个按钮,这只是根据设备大小的高度滚动页面..

    一些简单的..如果你想试试这个...(这是我的个人意见,可能我错了)

    【讨论】:

    • 是的,webview 提供了这么多功能。
    • 你能举个例子说明在 epub 文件中使用 webview 的搜索和书签功能吗
    • 文字在底部和顶部被截断如何处理?
    【解决方案3】:

    有一个处理分页问题的 javascript 库

    http://monocle.inventivelabs.com.au/

    本项目在android中使用

    https://github.com/sharathpuranik/chaek-android

    获取源代码并查看。

    【讨论】: