android项目源码解析03——vudroid阅读器源码解析03:文件内容显示


       本文要讲的是,vudroid阅读器选择某个文件后,如何展示该文件的内容。

       这里不涉及vudroid是如何读取文件内容的,只是涉及读取到文件内容后,如何展示这些内容。

       这里涉及到三个类:DocumentView,Page,PageTreeNode。

       DocumentView我们可以认为是一个显示容器,它里面存放的内容是一个个的页(Page),而每个页是由若干个PageTreeNode组成的。

       因此,我们可以看到,DocumentView只是负责处理触摸屏时间、按钮时间、滚动事件,当然这里还涉及到放大缩小这个功能的处理;而Page是包括一页的内容,包括页边界、文本内容等;PageTreeNode中存放的才是真正的文本内容。


1、DocumentView

        这里要做的内容包括按键处理、触摸屏事件处理(支持多点触摸)、放大缩小功能处理、scroll事件处理:

1)按键事件处理,这里你按上下左右键,页面内容是可以上下左右移动的。

@Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    lineByLineMoveTo(1);
                    return true;
                case KeyEvent.KEYCODE_DPAD_LEFT:
                    lineByLineMoveTo(-1);
                    return true;
                case KeyEvent.KEYCODE_DPAD_DOWN:
                    verticalDpadScroll(1);
                    return true;
                case KeyEvent.KEYCODE_DPAD_UP:
                    verticalDpadScroll(-1);
                    return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }
2)触摸屏事件处理(这里由于引入了多点触摸的库,因此是支持多点触摸的)

第一段代码时倒入多点触摸的库

private void initMultiTouchZoomIfAvailable(ZoomModel zoomModel) {
        try {
            multiTouchZoom = (MultiTouchZoom) Class.forName("org.vudroid.core.multitouch.MultiTouchZoomImpl").getConstructor(ZoomModel.class).newInstance(zoomModel);
        } catch (Exception e) {
            System.out.println("Multi touch zoom is not available: " + e);
        }
    }
第二段代码是处理触摸屏事件

 @Override
    public boolean onTouchEvent(MotionEvent ev) {
        super.onTouchEvent(ev);

        if (multiTouchZoom != null) {
            if (multiTouchZoom.onTouchEvent(ev)) {
                return true;
            }

            if (multiTouchZoom.isResetLastPointAfterZoom()) {
                setLastPosition(ev);
                multiTouchZoom.setResetLastPointAfterZoom(false);
            }
        }

        if (velocityTracker == null) {
            velocityTracker = VelocityTracker.obtain();
        }
        velocityTracker.addMovement(ev);

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                stopScroller();
                setLastPosition(ev);
                if (ev.getEventTime() - lastDownEventTime < DOUBLE_TAP_TIME) {
                    zoomModel.toggleZoomControls();
                } else {
                    lastDownEventTime = ev.getEventTime();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                scrollBy((int) (lastX - ev.getX()), (int) (lastY - ev.getY()));
                setLastPosition(ev);
                break;
            case MotionEvent.ACTION_UP:
                velocityTracker.computeCurrentVelocity(1000);
                scroller.fling(getScrollX(), getScrollY(), (int) -velocityTracker.getXVelocity(), (int) -velocityTracker.getYVelocity(), getLeftLimit(), getRightLimit(), getTopLimit(), getBottomLimit());
                velocityTracker.recycle();
                velocityTracker = null;

                break;
        }
        return true;
    }
        这段代码中,首先是让多点触摸的处理类处理事件,如果该事件在这里不被处理,则按普通触摸屏事件(区别于多点触摸)处理。

3)、缩放功能处理

public void zoomChanged(float newZoom, float oldZoom) {
        inZoom = true;
        stopScroller();
        final float ratio = newZoom / oldZoom;
        invalidatePageSizes();
        scrollTo((int) ((getScrollX() + getWidth() / 2) * ratio - getWidth() / 2), (int) ((getScrollY() + getHeight() / 2) * ratio - getHeight() / 2));
        postInvalidate();
    }
这个应该是由ZoomListener触发的事件,具体可以研究下ZoomListener的代码。

4)scroll事件处理

        只要调用了scrollTo和scrollBy都会触发onScrollChanged函数。该函数的代码是所有DocumentView事件的基础,因为其他事件最终都会调用这一个代码。

@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        // bounds could be not updated
        post(new Runnable() {
            public void run() {
                currentPageModel.setCurrentPageIndex(getCurrentPage());
            }
        });
        if (inZoom) {
            return;
        }
        // on scrollChanged can be called from scrollTo just after new layout applied so we should wait for relayout
        post(new Runnable() {
            public void run() {
                updatePageVisibility();
            }
        });
    }
        这里我们看到,DocumentView中要改变显示内容的话,最终都是通过更改每个Page的显示来实现的。读这一段代码的时候要注意以下这段函数:

void invalidatePageSizes() {
        if (!isInitialized) {
            return;
        }
        float heightAccum = 0;
        int width = getWidth();
        float zoom = zoomModel.getZoom();
        for (int i = 0; i < pages.size(); i++) {
            Page page = pages.get(i);
            float pageHeight = page.getPageHeight(width, zoom);
            page.setBounds(new RectF(0, heightAccum, width * zoom, heightAccum + pageHeight));
            heightAccum += pageHeight;
        }
    }
        这一端代码定义每一页的大小。根据PageTreeNode中的代码判断,这一部分显示是这样的,pages中的内容,我们可以看作是一页页首尾连在一起的卷轴,DocumentView相当于一个放大镜,这个放大镜放到什么地方,就显示什么内容。

2、page

        说实在的,我没有搞清楚有了page以后,让page来显示内容就可以了,为什么要加一个PageTreeNode类?

        page类的功能实际上很直白:显示一页内容的上下分界线,滑动到某页时在其中间显示当前页数(这个黑体页数值会被PageTreeNode的内容覆盖,可以认为是文件内容没有显示之前,先显示一个页数值)。

3、PageTreeNode

        PageTreeNode类是用来显示文件内容的,就是你在屏幕上看得到的实实在在的阅读内容。

       从以下函数知道PageTreeNode中的内容在PageTreeNode的方框与documentView的方框有交集时可以显示。

private boolean isVisible() {
        return RectF.intersects(documentView.getViewRect(), getTargetRectF());
    }
     但是我没弄明白pageSliceBounds、children、thresholdHit()等等这些成员是拿来做什么的。从DecodeServiceBase的代码中可以看出pageSliceBounds与读取具体某种格式的文件(如pdf文件)有关系,但其具体在什么地方有用,也只有等阅读以下读取pdf的那些代码才能搞明白了。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值