HTMLファイルのコンテンツを画面サイズのチャンクに分割して、WebKitブラウザーで「ページ分割」するにはどうすればよいですか?
各「ページ」には、テキスト全体が表示されます。これは、テキストの行を画面の上部または下部の境界で半分にカットしてはならないことを意味します。
編集
私の意図はAndroid ePubリーダーを作成することです。プラットフォームに依存しない質問。
ここでのダンの答えに基づいて、この問題に対する私の解決策は、今まで苦労していたことです。 (この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;
お役に立てれば...
経験から言えば、ベアボーンビューアーであっても、これに多くの時間を費やすことを期待してください。 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を貼り付けて、プログラムを実行するときに名前の一部を入力してください書籍の詳細が表示されます。
数冊の本で正常に機能していましたが、Googleブックスの電子書籍で完全に壊れました。他の情報源からの本と比較して、彼らは(少なくとも私にとっては)ePubの完全に奇妙な実装を持っています。
とにかく、うまくいけばそこにある構造コードのいくつかがあなたを助けるかもしれません!
私もこのようなものをコーディングしなければならなかった、と私の(作業)ソリューションはこれです:
これらの行をウェブビューに適用する必要があります...
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()");
}
楽しい :)
最近、これに似たものを試み、CSSスタイリングを追加して、レイアウトを垂直ではなく水平に変更しました。これにより、Epubのコンテンツを変更する必要なく、望ましい効果が得られました。
このコードshould動作します。
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");
したがって、基本的には、チャプターが読み込まれた後にbody要素のスタイルを変更するためにJavaScriptを注入しています(非常に重要です)。このアプローチの唯一の欠点は、コンテンツに画像がある場合、計算された列数が斜めになることです。ただし、修正するのはそれほど難しくないはずです。私の試みは、DOM内のすべての画像に幅と高さの属性を追加するJavaScriptを挿入することでした。
それが役に立てば幸い。
-ダン
XSL-FO を使用するとうまくいくかもしれません。これはモバイルデバイスにとっては重そうに思えますが、多すぎるかもしれませんが、うまくいくはずです。また、適切なページネーションの複雑さを実装する必要はありません(たとえば、各画面がテキストを半分にカットしないようにする方法) 。
基本的な考え方は次のとおりです。
Androidで利用可能なXSL-FOプロセッサがあるかどうかはわかりません。 Apache FOPを試すことができます。 RenderX(XSL-FOプロセッサ)には paged-HTML出力オプション があるという利点がありますが、Androidで実行できるかどうかはわかりません。
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;
}
}
最近この同じ問題があり、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
これにはいくつかの方法があります。すべての行が独自の要素内にある場合、その端の1つがビュー(ブラウザーまたは「ブックページ」)の外側にあるかどうかを確認するだけです。
事前にいくつの「ページ」があるかを知りたい場合は、一時的にそれらをビューに移動し、ページが終了する行を取得します。ブラウザが何かを知るためにページのリフローが必要なため、これは潜在的に遅い可能性があります。
そうでなければ、HTML5キャンバス要素を使用して、テキストを測定したり、テキストを描画したりできると思います。
これに関するいくつかの情報: https://developer.mozilla.org/en/Drawing_text_using_a_canvashttp://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa- excanvas.js/demo/8_2_canvas_measureText.html
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を検査してください。
リンクが機能しない場合は、コメント-修正してください。
ページを個別のXHTMLファイルに分割して、フォルダーに保存できます。例:page01、page02。その後、これらのページを1つずつ下にレンダリングできます。