HTML 书本式分页
Posted
技术标签:
【中文标题】HTML 书本式分页【英文标题】:HTML book-like pagination 【发布时间】:2011-04-07 20:31:13 【问题描述】:如何将 html 文件的内容拆分为屏幕大小的块,以便在 WebKit 浏览器中对其进行“分页”?
每个“页面”都应显示完整的文本量。这意味着一行文本不得在屏幕的顶部或底部边框中被切成两半。
编辑
这个问题最初被标记为“android”,因为我的目的是构建一个 Android ePub 阅读器。但是,该解决方案似乎可以仅使用 javascript 和 CSS 来实现,因此我扩大了问题的范围以使其与平台无关。
【问题讨论】:
"我如何将 XHTML 文件的内容分成屏幕大小的块来“分页”这本书。" -- 为什么要这样做? 因为它是一种类似于书本且被广泛使用的方式(即:Aldiko)来呈现文本,而且它也是一个有趣的问题。 :) 嗨,以下哪种解决方案适合你。现在我面临和你一样的问题 -:( 兄弟...你能得到解决方案吗..我非常需要它...请 EPUB 相同:***.com/questions/2808652/… 【参考方案1】:您可以将页面拆分为单独的 XHTML 文件并将它们存储在一个文件夹中。例如:page01、page02。然后,您可以将这些页面一张一张地呈现在彼此的下方。
【讨论】:
我怎么知道根据屏幕和字体大小在哪里分割?【参考方案2】:根据经验,即使对于准系统观众来说,也需要投入大量时间。 ePub 阅读器实际上是我开始学习 C# 时接手的第一个大项目,但 ePub 标准肯定相当复杂。
您可以在此处找到最新版本的 ePub 规范: http://www.idpf.org/specs.htm 其中包括 OPS(Open Publication Structure)、OPF(Open Packaging Format)和 OCF(OEBPS Container Format)。
另外,如果它对你有帮助,这里是我开始的项目的 C# 源代码的链接:
https://www.dropbox.com/sh/50kxcr29831t854/MDITIklW3I/ePub%20Test.zip
它根本没有充实;我已经好几个月没玩这个了,但如果我没记错的话,只需在调试目录中粘贴一个 ePub,然后在运行程序时输入名称的一部分(例如在 Dome 下,只需输入“dome”)它将显示该书的详细信息。
我让它在几本书上都能正常工作,但谷歌图书中的任何电子书都完全破坏了它。与其他来源的书籍相比,他们对 ePub 的实现完全奇怪(至少对我而言)。
无论如何,希望其中的一些结构代码可以帮助您!
【讨论】:
【参考方案3】:我最近尝试了类似的方法并添加了一些 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 以在章节加载后更改正文元素的样式(非常重要)。这种方法的唯一缺点是当内容中有图像时,计算的列数会出现偏差。不过修复起来应该不会太难。我的尝试是注入一些 JavaScript 来为 DOM 中没有任何图像的所有图像添加宽度和高度属性。
希望对你有帮助。
-丹
【讨论】:
+1 无法让它发挥作用,但我认为它为我指明了正确的方向。 @Dan 你能分享一下你的css风格吗?分页对我有用,但同样需要 css。请发布您的CSS。提前致谢。【参考方案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 上运行。
【讨论】:
【参考方案5】:以 Dan 的回答为基础,这是我对这个问题的解决方案,直到现在我一直在努力解决这个问题。 (此 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;
希望这会有所帮助...
【讨论】:
你能指导我如何在 webview 中实现这个吗?或者你可以为此发布整个代码吗?提前致谢。【参考方案6】:您可以查看http://www.litres.ru/static/OR/or.html?data=/static/trials/00/42/47/00424722.gur.html&art=424722&user=0&trial=1,但代码可能被严重混淆,因此只需使用 Firebug 来检查 DOM。
如果链接不起作用,请发表评论 - 会给你修复。
【讨论】:
【参考方案7】:有几种方法可以做到这一点。如果每一行都在它自己的元素中,你所要做的就是检查它的一个边缘是否超出了视图(浏览器或“书页”)。
如果您想提前知道会有多少“页面”,只需将它们临时移动到视图中并获取页面结束的行。这可能会很慢,因为浏览器需要页面重排才能知道任何东西在哪里。
否则我认为您可以使用 HTML5 画布元素来测量文本和/或绘制文本。
这里的一些信息: 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
【讨论】:
【参考方案8】:我也不得不编写类似的代码,我的(工作)解决方案是这样的:
您必须将这些行应用到 webview...
webView_.getSettings().setUseWideViewPort(true);
webView_.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
此外,您必须注入一些 javascript。我的活动的不同规模和 web 视图中呈现的内容有很多问题,所以我的解决方案没有从“外部”获取任何价值。
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()");
享受:)
【讨论】:
这行得通。如何在单击按钮时滚动到下一列? @Midhun,$("body").animate(scrollLeft: window.innerWidth*<your col index>);
如何使用此代码进行滚动页面分页?
这很好用,但有一个问题。我可以向下滚动,底部有很多额外的空间。如何删除这个多余的空间?
js字符串中的currentPage
变量有什么用?【参考方案9】:
最近遇到了同样的问题,并受到答案的启发,找到了一个使用 CSS3 的 column-* 属性的普通 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 上给出了很好的结果。使用不同的属性会产生不同的页面间距等。
如果您需要支持多个章节,例如需要从新页面开始,github 上有一个 XCode 5 示例:https://github.com/dmrschmidt/ios_uiwebview_pagination
【讨论】:
【参考方案10】:我能够改进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 中获取我传递给自定义 HorizontalWebView 以实现分页效果的水平页面数
HorizontalWebView.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;
【讨论】:
以上是关于HTML 书本式分页的主要内容,如果未能解决你的问题,请参考以下文章