HTML-книжная нумерация страниц - PullRequest
59 голосов
/ 03 сентября 2010

Как разделить содержимое файла HTML на куски размером с экран, чтобы «разбить» его на страницы в браузере WebKit?

Каждая «страница» должна отображать полный объем текста.Это означает, что строка текста не должна быть разрезана пополам в верхней или нижней границе экрана.

Редактировать

Этот вопрос был изначально помечен как "Android"так как мое намерение состоит в том, чтобы создать Android ePub Reader.Однако, похоже, что решение может быть реализовано только с помощью JavaScript и CSS, поэтому я расширил сферу вопроса, чтобы сделать его независимым от платформы.

Ответы [ 10 ]

30 голосов
/ 05 октября 2010

Опираясь на ответ Дэна, я решил эту проблему, с которой я до сих пор боролся.(этот 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;

Надеюсь, это поможет ...

21 голосов
/ 03 сентября 2010

Исходя из опыта, ожидайте, что потратите на это много времени, даже для зрителей с минимальными возможностями.Читатель 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 в каталог отладки, а когда вы запускаете программу, просто введите некоторую часть имени (например, «Под куполом», просто введите «купол»)и он будет отображать детали книги.

У меня он работал правильно для нескольких книг, но любые электронные книги из Google Книг сломали его полностью.У них совершенно странная реализация ePub (по крайней мере для меня) по сравнению с книгами из других источников.

В любом случае, надеюсь, вам поможет какой-то структурный код!

18 голосов
/ 06 февраля 2012

Мне тоже пришлось написать что-то подобное, и мое (рабочее) решение таково:

Вы должны применить эти строки к веб-представлению ...

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

Кроме того, вам нужно добавить немного javascript. У меня было множество проблем с различными масштабами моей деятельности и содержанием, отображаемым в веб-представлении, поэтому мое решение не принимает никакой ценности извне.

    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()");
    }

Наслаждайтесь:)

12 голосов
/ 14 сентября 2010

Недавно я попытался сделать что-то похожее на это и добавил несколько стилей 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, у которых их нет.

Надеюсь, это поможет.

4 голосов
/ 15 сентября 2010

Возможно, будет работать XSL-FO . Это кажется тяжелым для мобильного устройства, и, возможно, это излишне, но это должно сработать, и вам не придется реализовывать сложности хорошего разбиения на страницы (например, как вы убедитесь, что каждый экран не разрезает текст пополам) самостоятельно .

Основная идея будет:

  • преобразовать XHTML (и другие файлы EPUB) в XSL-FO, используя XSLT.
  • используйте процессор XSL-FO для рендеринга XSL-FO в постраничный формат, который вы можете отобразить на мобильном устройстве, например, в формате PDF (вы можете отобразить это?)

Я не знаю, существует ли процессор Android для XSL-FO. Вы можете попробовать Apache FOP. RenderX (процессор XSL-FO) имеет преимущество, заключающееся в возможности вывода paged-HTML , но, опять же, я не знаю, может ли он работать на Android.

1 голос
/ 24 июня 2017

Мне удалось улучшить Решение Nacho , чтобы получить эффект горизонтальной прокрутки с помощью WebView. Вы можете найти решение здесь и пример код .

Edit:

Код решения.

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())");
}

В onJsAlert моего WebChromeClient получите количество горизонтальных страниц, которые я передаю в пользовательский 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;
    }
}
1 голос
/ 01 ноября 2013

Если бы эта проблема возникла недавно и вдохновилась ответами, она нашла простое решение CSS с использованием атрибутов column- * CSS3:

/* 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 голос
/ 07 октября 2010

Есть несколько способов сделать это. Если каждая строка находится в своем собственном элементе, все, что вам нужно сделать, это проверить, не выходит ли один из ее краев за пределы представления (либо браузеры, либо «страница книги»).

Если вы хотите знать, сколько «страниц» будет заранее, просто временно переместите их в представление и определите, какая строка заканчивается страницей. Это может потенциально быть медленным, потому что для того, чтобы браузер знал, где что находится, требуется перекомпоновка страницы.

В противном случае я думаю, что вы могли бы использовать элемент HTML5 canvas для измерения текста и / или рисования текста.

Некоторая информация об этом здесь: https://developer.mozilla.org/en/Drawing_text_using_a_canvas http://uupaa -js-spinoff.googlecode.com / SVN / багажник / uupaa-excanvas.js / демо / 8_2_canvas_measureText.html

0 голосов
/ 05 октября 2010

Вы можете посмотреть на 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.

Если ссылка не работает, прокомментируйте - вы получите исправление.

0 голосов
/ 03 сентября 2010

Вы можете разделить страницы на отдельные файлы XHTML и сохранить их в папке.Например: страница 01, страница 02.Затем вы можете отобразить эти страницы одну под другой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...