Просмотрщик андроида PDF с вертикальным поисковым вызовом

Я разрабатываю приложение для Android, которое имеет PDF для просмотра. PDF-файлы встроены в приложение, поэтому мне нужно просто загрузить PDF для правильного просмотра.

Не должно быть возможности делиться и другими вещами, но пользователь должен иметь возможность масштабировать pdf.

Я использовал mupdf, но pdf прокручивает по горизонтали (то есть страницы бок о бок), я хочу, чтобы pdf прокручивался по вертикали. Я пробовал все, но я не получаю результата.

Вы можете изменить горизонтальные значения по вертикали (изменить все вычисления, связанные с шириной, на высоту). Измените onLayout () и onFling (), как показано ниже:

@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // "Edit mode" means when the View is being displayed in the Android GUI editor. (this class // is instantiated in the IDE, so we need to be a bit careful what we do). if (isInEditMode()) return; View cv = mChildViews.get(mCurrent); Point cvOffset; if (!mResetLayout) { // Move to next or previous if current is sufficiently off center if (cv != null) { cvOffset = subScreenSizeOffset(cv); // cv.getRight() may be out of date with the current scale // so add left to the measured width for the correct position //if (cv.getLeft() + cv.getMeasuredWidth() + cvOffset.x + GAP/2 + mXScroll < getWidth()/2 && mCurrent + 1 < mAdapter.getCount()) { if (cv.getTop() + cv.getMeasuredHeight() + cvOffset.y + GAP / 2 + mYScroll < getHeight() / 2 && mCurrent + 1 < mAdapter.getCount()) { postUnsettle(cv); // post to invoke test for end of animation // where we must set hq area for the new current view mStepper.prod(); onMoveOffChild(mCurrent); mCurrent++; onMoveToChild(mCurrent); } //if (cv.getLeft() - cvOffset.x - GAP/2 + mXScroll >= getWidth()/2 && mCurrent > 0) { if (cv.getTop() - cvOffset.y - GAP / 2 + mYScroll >= getHeight() / 2 && mCurrent > 0) { postUnsettle(cv); // post to invoke test for end of animation // where we must set hq area for the new current view mStepper.prod(); onMoveOffChild(mCurrent); mCurrent--; onMoveToChild(mCurrent); } } // Remove not needed children and hold them for reuse int numChildren = mChildViews.size(); int childIndices[] = new int[numChildren]; for (int i = 0; i < numChildren; i++) childIndices[i] = mChildViews.keyAt(i); for (int i = 0; i < numChildren; i++) { int ai = childIndices[i]; if (ai < mCurrent - 1 || ai > mCurrent + 1) { View v = mChildViews.get(ai); onNotInUse(v); mViewCache.add(v); removeViewInLayout(v); mChildViews.remove(ai); } } } else { mResetLayout = false; mXScroll = mYScroll = 0; // Remove all children and hold them for reuse int numChildren = mChildViews.size(); for (int i = 0; i < numChildren; i++) { View v = mChildViews.valueAt(i); onNotInUse(v); mViewCache.add(v); removeViewInLayout(v); } mChildViews.clear(); // Don't reuse cached views if the adapter has changed if (mReflowChanged) { mReflowChanged = false; mViewCache.clear(); } // post to ensure generation of hq area mStepper.prod(); } // Ensure current view is present int cvLeft, cvRight, cvTop, cvBottom; boolean notPresent = (mChildViews.get(mCurrent) == null); cv = getOrCreateChild(mCurrent); // When the view is sub-screen-size in either dimension we // offset it to center within the screen area, and to keep // the views spaced out cvOffset = subScreenSizeOffset(cv); if (notPresent) { //Main item not already present. Just place it top left cvLeft = cvOffset.x; cvTop = cvOffset.y; } else { // Main item already present. Adjust by scroll offsets cvLeft = cv.getLeft() + mXScroll; cvTop = cv.getTop() + mYScroll; } // Scroll values have been accounted for mXScroll = mYScroll = 0; cvRight = cvLeft + cv.getMeasuredWidth(); cvBottom = cvTop + cv.getMeasuredHeight(); if (!mUserInteracting && mScroller.isFinished()) { Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom)); cvRight += corr.x; cvLeft += corr.x; cvTop += corr.y; cvBottom += corr.y; } else if (cv.getMeasuredWidth() <= getWidth()) { // // When the current view is as small as the screen in height, clamp // // it vertically // Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom)); // cvTop += corr.y; // cvBottom += corr.y; // When the current view is as small as the screen in width, clamp // it horizontally Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom)); cvRight += corr.x; cvLeft += corr.x; } cv.layout(cvLeft, cvTop, cvRight, cvBottom); if (mCurrent > 0) { View lv = getOrCreateChild(mCurrent - 1); Point leftOffset = subScreenSizeOffset(lv); /*int gap = leftOffset.x + GAP + cvOffset.x; lv.layout(cvLeft - lv.getMeasuredWidth() - gap, (cvBottom + cvTop - lv.getMeasuredHeight())/2, cvLeft - gap, (cvBottom + cvTop + lv.getMeasuredHeight())/2);*/ int gap = leftOffset.y + GAP + cvOffset.y; lv.layout((cvRight + cvLeft - lv.getMeasuredWidth())/2, cvTop - lv.getMeasuredHeight() - gap, (cvRight + cvLeft + lv.getMeasuredWidth())/2, cvTop - gap); } if (mCurrent + 1 < mAdapter.getCount()) { View rv = getOrCreateChild(mCurrent + 1); Point rightOffset = subScreenSizeOffset(rv); /*int gap = cvOffset.x + GAP + rightOffset.x; rv.layout(cvRight + gap, (cvBottom + cvTop - rv.getMeasuredHeight())/2, cvRight + rv.getMeasuredWidth() + gap, (cvBottom + cvTop + rv.getMeasuredHeight())/2);*/ int gap = cvOffset.y + GAP + rightOffset.y; rv.layout((cvRight + cvLeft - rv.getMeasuredWidth())/2, cvBottom + gap, (cvRight + cvLeft + rv.getMeasuredWidth())/2, cvBottom + rv.getMeasuredHeight() + gap); } invalidate(); } 

А также,

  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (mScaling) return true; View v = mChildViews.get(mCurrent); if (v != null) { Rect bounds = getScrollBounds(v); switch (directionOfTravel(velocityX, velocityY)) { case MOVING_UP: if (bounds.top >= 0) { // Fling off to the left bring next view onto screen View vl = mChildViews.get(mCurrent + 1); if (vl != null) { slideViewOntoScreen(vl); return true; } } break; case MOVING_DOWN: if (bounds.bottom <= 0) { // Fling off to the right bring previous view onto screen View vr = mChildViews.get(mCurrent - 1); if (vr != null) { slideViewOntoScreen(vr); return true; } } break; } mScrollerLastX = mScrollerLastY = 0; // If the page has been dragged out of bounds then we want to spring back // nicely. fling jumps back into bounds instantly, so we don't want to use // fling in that case. On the other hand, we don't want to forgo a fling // just because of a slightly off-angle drag taking us out of bounds other // than in the direction of the drag, so we test for out of bounds only // in the direction of travel. // // Also don't fling if out of bounds in any direction by more than fling // margin Rect expandedBounds = new Rect(bounds); expandedBounds.inset(-FLING_MARGIN, -FLING_MARGIN); if (withinBoundsInDirectionOfTravel(bounds, velocityX, velocityY) && expandedBounds.contains(0, 0)) { mScroller.fling(0, 0, (int) velocityX, (int) velocityY, bounds.left, bounds.right, bounds.top, bounds.bottom); mStepper.prod(); } } return true; } 

Решение этого для MuPDF 1.9a просто изменяет следующую переменную в файле ReaderView.java;

 private static final boolean HORIZONTAL_SCROLLING = true; 

в

  private static final boolean HORIZONTAL_SCROLLING = false; 

Thx для ответа, отправленного @Arunjyothis, но я предоставил ниже класс, где присутствует ссылка на переменную:

ReaderView.java

  public class ReaderView extends AdapterView<Adapter> implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, Runnable { ... private Stepper mStepper; public ReaderView(Context context) { super(context); mGestureDetector = new GestureDetector(this); mScaleGestureDetector = new ScaleGestureDetector(context, this); mScroller = new Scroller(context); mStepper = new Stepper(this, this); } boolean mReflowChanged; @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // "Edit mode" means when the View is being displayed in the Android GUI editor. (this class // is instantiated in the IDE, so we need to be a bit careful what we do). if (isInEditMode()) return; View cv = mChildViews.get(mCurrent); Point cvOffset; if (!mResetLayout) { // Move to next or previous if current is sufficiently off center if (cv != null) { cvOffset = subScreenSizeOffset(cv); // cv.getRight() may be out of date with the current scale // so add left to the measured width for the correct position //if (cv.getLeft() + cv.getMeasuredWidth() + cvOffset.x + GAP/2 + mXScroll < getWidth()/2 && mCurrent + 1 < mAdapter.getCount()) { if (cv.getTop() + cv.getMeasuredHeight() + cvOffset.y + GAP / 2 + mYScroll < getHeight() / 2 && mCurrent + 1 < mAdapter.getCount()) { postUnsettle(cv); // post to invoke test for end of animation // where we must set hq area for the new current view mStepper.prod(); onMoveOffChild(mCurrent); mCurrent++; onMoveToChild(mCurrent); } //if (cv.getLeft() - cvOffset.x - GAP/2 + mXScroll >= getWidth()/2 && mCurrent > 0) { if (cv.getTop() - cvOffset.y - GAP / 2 + mYScroll >= getHeight() / 2 && mCurrent > 0) { postUnsettle(cv); // post to invoke test for end of animation // where we must set hq area for the new current view mStepper.prod(); onMoveOffChild(mCurrent); mCurrent--; onMoveToChild(mCurrent); } } // Remove not needed children and hold them for reuse int numChildren = mChildViews.size(); int childIndices[] = new int[numChildren]; for (int i = 0; i < numChildren; i++) childIndices[i] = mChildViews.keyAt(i); for (int i = 0; i < numChildren; i++) { int ai = childIndices[i]; if (ai < mCurrent - 1 || ai > mCurrent + 1) { View v = mChildViews.get(ai); onNotInUse(v); mViewCache.add(v); removeViewInLayout(v); mChildViews.remove(ai); } } } else { mResetLayout = false; mXScroll = mYScroll = 0; // Remove all children and hold them for reuse int numChildren = mChildViews.size(); for (int i = 0; i < numChildren; i++) { View v = mChildViews.valueAt(i); onNotInUse(v); mViewCache.add(v); removeViewInLayout(v); } mChildViews.clear(); // Don't reuse cached views if the adapter has changed if (mReflowChanged) { mReflowChanged = false; mViewCache.clear(); } // post to ensure generation of hq area mStepper.prod(); } // Ensure current view is present int cvLeft, cvRight, cvTop, cvBottom; boolean notPresent = (mChildViews.get(mCurrent) == null); cv = getOrCreateChild(mCurrent); // When the view is sub-screen-size in either dimension we // offset it to center within the screen area, and to keep // the views spaced out cvOffset = subScreenSizeOffset(cv); if (notPresent) { //Main item not already present. Just place it top left cvLeft = cvOffset.x; cvTop = cvOffset.y; } else { // Main item already present. Adjust by scroll offsets cvLeft = cv.getLeft() + mXScroll; cvTop = cv.getTop() + mYScroll; } // Scroll values have been accounted for mXScroll = mYScroll = 0; cvRight = cvLeft + cv.getMeasuredWidth(); cvBottom = cvTop + cv.getMeasuredHeight(); if (!mUserInteracting && mScroller.isFinished()) { Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom)); cvRight += corr.x; cvLeft += corr.x; cvTop += corr.y; cvBottom += corr.y; } else if (cv.getMeasuredWidth() <= getWidth()) { // // When the current view is as small as the screen in height, clamp // // it vertically // Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom)); // cvTop += corr.y; // cvBottom += corr.y; // When the current view is as small as the screen in width, clamp // it horizontally Point corr = getCorrection(getScrollBounds(cvLeft, cvTop, cvRight, cvBottom)); cvRight += corr.x; cvLeft += corr.x; } cv.layout(cvLeft, cvTop, cvRight, cvBottom); if (mCurrent > 0) { View lv = getOrCreateChild(mCurrent - 1); Point leftOffset = subScreenSizeOffset(lv); /*int gap = leftOffset.x + GAP + cvOffset.x; lv.layout(cvLeft - lv.getMeasuredWidth() - gap, (cvBottom + cvTop - lv.getMeasuredHeight())/2, cvLeft - gap, (cvBottom + cvTop + lv.getMeasuredHeight())/2);*/ int gap = leftOffset.y + GAP + cvOffset.y; lv.layout((cvRight + cvLeft - lv.getMeasuredWidth()) / 2, cvTop - lv.getMeasuredHeight() - gap, (cvRight + cvLeft + lv.getMeasuredWidth()) / 2, cvTop - gap); } if (mCurrent + 1 < mAdapter.getCount()) { View rv = getOrCreateChild(mCurrent + 1); Point rightOffset = subScreenSizeOffset(rv); /*int gap = cvOffset.x + GAP + rightOffset.x; rv.layout(cvRight + gap, (cvBottom + cvTop - rv.getMeasuredHeight())/2, cvRight + rv.getMeasuredWidth() + gap, (cvBottom + cvTop + rv.getMeasuredHeight())/2);*/ int gap = cvOffset.y + GAP + rightOffset.y; rv.layout((cvRight + cvLeft - rv.getMeasuredWidth()) / 2, cvBottom + gap, (cvRight + cvLeft + rv.getMeasuredWidth()) / 2, cvBottom + rv.getMeasuredHeight() + gap); } invalidate(); } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (mScaling) return true; View v = mChildViews.get(mCurrent); if (v != null) { Rect bounds = getScrollBounds(v); switch (directionOfTravel(velocityX, velocityY)) { case MOVING_UP: if (bounds.top >= 0) { // Fling off to the left bring next view onto screen View vl = mChildViews.get(mCurrent + 1); if (vl != null) { slideViewOntoScreen(vl); return true; } } break; case MOVING_DOWN: if (bounds.bottom <= 0) { // Fling off to the right bring previous view onto screen View vr = mChildViews.get(mCurrent - 1); if (vr != null) { slideViewOntoScreen(vr); return true; } } break; } mScrollerLastX = mScrollerLastY = 0; // If the page has been dragged out of bounds then we want to spring back // nicely. fling jumps back into bounds instantly, so we don't want to use // fling in that case. On the other hand, we don't want to forgo a fling // just because of a slightly off-angle drag taking us out of bounds other // than in the direction of the drag, so we test for out of bounds only // in the direction of travel. // // Also don't fling if out of bounds in any direction by more than fling // margin Rect expandedBounds = new Rect(bounds); expandedBounds.inset(-FLING_MARGIN, -FLING_MARGIN); if (withinBoundsInDirectionOfTravel(bounds, velocityX, velocityY) && expandedBounds.contains(0, 0)) { mScroller.fling(0, 0, (int) velocityX, (int) velocityY, bounds.left, bounds.right, bounds.top, bounds.bottom); mStepper.prod(); } } return true; } ... } 

Stepper.java

 public class Stepper { protected final View mPoster; protected final Runnable mTask; protected boolean mPending; public Stepper(View v, Runnable r) { mPoster = v; mTask = r; mPending = false; } @SuppressLint("NewApi") public void prod() { if (!mPending) { mPending = true; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mPoster.postOnAnimation(new Runnable() { @Override public void run() { mPending = false; mTask.run(); } }); } else { mPoster.post(new Runnable() { @Override public void run() { mPending = false; mTask.run(); } }); } } } }