2010-09-03 50 views
57

如何將HTML文件的內容以屏幕大小的塊分割爲WebKit瀏覽器中的「分頁」?HTML書樣分頁

每個「頁面」應顯示完整的文本量。這意味着在屏幕的頂部或底部邊框中不得將一行文本切成兩半。

編輯

這個問題最初是標記的「Android」作爲我的意圖是建立一個Android的ePub閱讀器。然而,似乎該解決方案只能通過JavaScript和CSS實現,因此我擴大了問題的範圍,使其與平臺無關。

+0

「我如何在屏幕上劃分XHTML文件的內容大塊「分頁」這本書。「 - 爲什麼這樣做? – CommonsWare 2010-09-03 14:02:47

+6

因爲它是一種類似書本和廣泛使用的方式(即:Aldiko)來呈現文本,而且這也是一個有趣的問題。 :) – hpique 2010-09-03 14:45:18

+0

嗨,下面的解決方案之一爲你工作。現在我面臨像你一樣的問題 - :( – DroidBot 2011-04-11 12:33:50

回答

30

建立在丹的答案在這裏是我對這個問題的解決方案,我一直在努力,直到現在。 (這個JS iOS上的Webkit的作品,爲Android沒有保證,但請讓我知道結果)

var desiredHeight; 
var desiredWidth; 
var bodyID = document.getElementsByTagName('body')[0]; 
totalHeight = bodyID.offsetHeight; 
pageCount = Math.floor(totalHeight/desiredHeight) + 1; 
bodyID.style.padding = 10; //(optional) prevents clipped letters around the edges 
bodyID.style.width = desiredWidth * pageCount; 
bodyID.style.height = desiredHeight; 
bodyID.style.WebkitColumnCount = pageCount; 

希望這有助於...

+6

你能指導我如何在webview中實現這個嗎?或者你可以發佈整個代碼嗎?提前致謝。 – 2012-08-28 11:19:53

0

您可以將頁面拆分爲單獨的XHTML文件並將它們存儲在一個文件夾中。例如:page01,page02。然後,您可以將這些頁面逐一呈現在彼此之下。

+0

我怎麼知道在哪裏分割屏幕和字體大小? – hpique 2010-09-03 13:25:56

21

從經驗來看,即使對於一個準系統的觀察者,也期望能夠投入大量時間。 ePub讀者實際上是我開始學習C#時首先承擔的大型項目,但ePub標準肯定非常複雜。

您可以找到最新版規範對於EPUB這裏: http://www.idpf.org/specs.htm 其中包括OPS(開放出版物結構),OPF(開放包裝格式),以及OCF(OEBPS容器格式​​)。

而且,如果它可以幫助你在所有的,這裏是該項目的C#源代碼的鏈接,我開始上:

https://www.dropbox.com/sh/50kxcr29831t854/MDITIklW3I/ePub%20Test.zip

它不充實可言;我幾個月都沒有玩過這個遊戲,但是如果我沒有記錯的話,只需將ePub粘貼到調試目錄中,然後在運行程序時只需輸入部分名稱即可(例如,在圓頂下,只需鍵入「dome」)並會顯示該書的詳細信息。

我曾經爲幾本書正確工作,但Google Books的任何電子書都完全破壞了它。與其他來源的書相比,他們對ePub的完全離奇實施(對我來說至少)。

無論如何,希望有一些在那裏的結構代碼可以幫助你!

+0

+1分享你的經驗和代碼 – hpique 2010-09-03 15:59:49

12

我最近嘗試了類似的東西,並添加了一些CSS樣式來將佈局更改爲水平而不是垂直。這給了我想要的效果,而無需以任何方式修改Epub的內容。

此代碼應該工作。

mWebView.setWebViewClient(new WebViewClient() { 
    public void onPageFinished(WebView view, String url) { 

     // Column Count is just the number of 'screens' of text. Add one for partial 'screens' 
     int columnCount = Math.floor(view.getHeight()/view.getWidth())+1; 

     // Must be expressed as a percentage. If not set then the WebView will not stretch to give the desired effect. 
     int columnWidth = columnCount * 100; 

     String js = "var d = document.getElementsByTagName('body')[0];" + 
      "d.style.WebkitColumnCount=" + columnCount + ";" + 
      "d.style.WebkitColumnWidth='" + columnWidth + "%';"; 
     mWebView.loadUrl("javascript:(function(){" + js + "})()"); 
    } 
}); 

mWebView.loadUrl("file:///android_asset/chapter.xml"); 

所以,基本上你是注入JavaScript來改變加載章節後的body元素的樣式(非常重要)。這種方法唯一的缺點是當內容中的圖像計算列數歪斜時。儘管如此,修復應該不會太難。我的嘗試是注入一些JavaScript來將寬度和高度屬性添加到DOM中沒有任何圖像的所有圖像。

希望它有幫助。

-Dan

+1

+1不能讓這個工作,但我認爲它已經指出我在正確的方向 – hpique 2010-10-02 15:00:05

+1

@丹我應該在哪裏添加此代碼? – Atihska 2014-01-30 00:48:39

+0

@丹你能分享我你的CSS風格,分頁適合我,但需要css相同。請張貼你的css。在此先感謝。 – 2015-12-31 05:59:07

4

也許它會工作使用XSL-FO。這對於移動設備來說似乎很沉重,也許它太過分了,但它應該可以工作,而且你不必執行好分頁的複雜性(例如,你如何確保每個屏幕不會將文本減半) 。

的基本思路是:

  • 使用XSLT轉換XHTML(和其他EPUB東西),以XSL-FO。
  • 使用XSL-FO處理器的XSL-FO渲染成如PDF分頁格式,您可以在移動設備上顯示,(你可以顯示?)

我不知道是否有一款適用於Android的XSL-FO處理器。你可以試試Apache FOP。 RenderX(XSL-FO處理器)具有paged-HTML output option的優勢,但我不知道它是否可以在Android上運行。

1

有幾種方法可以完成。如果每行都在自己的元素中,您只需檢查其中一條邊是否超出視圖(瀏覽器或「書頁」)。

如果您想知道將會提前多少個「頁面」,只需暫時將它們移動到視圖中並獲取頁面結束的內容。這可能會很慢,因爲瀏覽器需要重新排列頁面才能知道任何內容。

否則,我認爲您可以使用HTML5 canvas元素來測量文本和/或繪製文本。

在這裏的一些信息: https://developer.mozilla.org/en/Drawing_text_using_a_canvas http://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa-excanvas.js/demo/8_2_canvas_measureText.html

18

我已經過編寫這樣的事情,我的(工作)的解決方案是這樣的:

你必須將這些線將webview ...

webView_.getSettings().setUseWideViewPort(true); 
    webView_.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); 

此外,你必須注入一些JavaScript。我的活動規模和webview中呈現的內容有很多問題,所以我的解決方案不會從「外部」獲取任何價值。

webView_.setWebViewClient(new WebViewClient(){ 

      public void onPageFinished(WebView view, String url) { 
       injectJavascript(); 
      } 

     }); 

[...]

public void injectJavascript() { 
     String js = "javascript:function initialize() { " + 
       "var d = document.getElementsByTagName('body')[0];" + 
       "var ourH = window.innerHeight; " + 
       "var ourW = window.innerWidth; " + 
       "var fullH = d.offsetHeight; " + 
       "var pageCount = Math.floor(fullH/ourH)+1;" + 
       "var currentPage = 0; " + 
       "var newW = pageCount*ourW; " + 
       "d.style.height = ourH+'px';" + 
       "d.style.width = newW+'px';" + 
       "d.style.webkitColumnGap = '2px'; " + 
       "d.style.margin = 0; " + 
       "d.style.webkitColumnCount = pageCount;" + 
       "}"; 
     webView_.loadUrl(js); 
     webView_.loadUrl("javascript:initialize()"); 
    } 

享受:)

+0

這有效。我怎樣才能滾動到按鈕點擊下一列? – Midhun 2013-12-17 07:43:02

+0

@Midhun,'$(「body」)。animate {{scrollLeft:window.innerWidth * <您的col索引}};' – Jmorvan 2014-01-10 14:27:32

+0

如何使用此代碼進行頁面分頁滾動? – 2016-02-24 08:52:06

1

最近有同樣的問題和答案的啓發發現使用CSS3的欄柱*屬性的純CSS解決方案:

/* CSS */ 
.chapter { 
    width: 600px; 
    padding: 60px 10px; 
    -webkit-column-gap: 40px; 
    -webkit-column-width: 150px; 
    -webkit-column-count: 2; 
    height:400px; 
} 

/* HTML */ 
<div class="chapter"> 
    your long lorem ipsum arbitrary HTML 
</div> 

上面的例子給出了很大的成績在視網膜iPhone上。使用不同的屬性來產生頁面之間的不同間距等。

如果您需要支持,例如多個章節這就需要開始新的頁面,有一個Xcode 5例子在github:https://github.com/dmrschmidt/ios_uiwebview_pagination

1

我是能夠提高Nacho's解決方案,使用的WebView水平刷卡分頁效果。您可以找到解決方案here和示例code

編輯:

解決方案的代碼。

MainActivity.java

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 
     WebView.setWebContentsDebuggingEnabled(true); 
    } 
    wv = (HorizontalWebView) findViewById(R.id.web_view); 
    wv.getSettings().setJavaScriptEnabled(true); 
    wv.setWebViewClient(new WebViewClient() { 

     public void onPageFinished(WebView view, String url) { 
      injectJavascript(); 
     } 
    }); 

    wv.setWebChromeClient(new WebChromeClient() { 
     @Override 
     public boolean onJsAlert(WebView view, String url, String message, JsResult result) { 
      int pageCount = Integer.parseInt(message); 
      wv.setPageCount(pageCount); 
      result.confirm(); 
      return true; 
     } 
    }); 
    wv.loadUrl("file:///android_asset/ch03.html"); // now it will not fail here 
} 

private void injectJavascript() { 
    String js = "function initialize(){\n" + 
      " var d = document.getElementsByTagName('body')[0];\n" + 
      " var ourH = window.innerHeight;\n" + 
      " var ourW = window.innerWidth;\n" + 
      " var fullH = d.offsetHeight;\n" + 
      " var pageCount = Math.floor(fullH/ourH)+1;\n" + 
      " var currentPage = 0;\n" + 
      " var newW = pageCount*ourW;\n" + 
      " d.style.height = ourH+'px';\n" + 
      " d.style.width = newW+'px';\n" + 
      " d.style.margin = 0;\n" + 
      " d.style.webkitColumnCount = pageCount;\n" + 
      " return pageCount;\n" + 
      "}"; 
    wv.loadUrl("javascript:" + js); 
    wv.loadUrl("javascript:alert(initialize())"); 
} 

在我WebChromeClient的onJsAlert讓我傳遞給定製Horizo​​ntalWebView實現分頁效果水平的頁數

Horizo​​ntalWebView.java

public class HorizontalWebView extends WebView { 
    private float x1 = -1; 
    private int pageCount = 0; 

    public HorizontalWebView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       x1 = event.getX(); 
       break; 
      case MotionEvent.ACTION_UP: 
       float x2 = event.getX(); 
       float deltaX = x2 - x1; 
       if (Math.abs(deltaX) > 100) { 
        // Left to Right swipe action 
        if (x2 > x1) { 
         turnPageLeft(); 
         return true; 
        } 

        // Right to left swipe action 
        else { 
         turnPageRight(); 
         return true; 
        } 

       } 
       break; 
     } 
     return true; 
    } 

    private int current_x = 0; 

    private void turnPageLeft() { 
     if (getCurrentPage() > 0) { 
      int scrollX = getPrevPagePosition(); 
      loadAnimation(scrollX); 
      current_x = scrollX; 
      scrollTo(scrollX, 0); 
     } 
    } 

    private int getPrevPagePosition() { 
     int prevPage = getCurrentPage() - 1; 
     return (int) Math.ceil(prevPage * this.getMeasuredWidth()); 
    } 

    private void turnPageRight() { 
     if (getCurrentPage() < pageCount - 1) { 
      int scrollX = getNextPagePosition(); 
      loadAnimation(scrollX); 
      current_x = scrollX; 
      scrollTo(scrollX, 0); 
     } 
    } 

    private void loadAnimation(int scrollX) { 
     ObjectAnimator anim = ObjectAnimator.ofInt(this, "scrollX", 
       current_x, scrollX); 
     anim.setDuration(500); 
     anim.setInterpolator(new LinearInterpolator()); 
     anim.start(); 
    } 

    private int getNextPagePosition() { 
     int nextPage = getCurrentPage() + 1; 
     return (int) Math.ceil(nextPage * this.getMeasuredWidth()); 
    } 

    public int getCurrentPage() { 
     return (int) (Math.ceil((double) getScrollX()/this.getMeasuredWidth())); 
    } 

    public void setPageCount(int pageCount) { 
     this.pageCount = pageCount; 
    } 
}