Commit 9e5231ef authored by wanglei's avatar wanglei

...

parent c01833f8
package com.artifex.mupdf.viewer
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.Point
import android.net.Uri
import android.util.DisplayMetrics
import android.view.View
import android.view.animation.Animation
import android.view.animation.TranslateAnimation
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import androidx.activity.addCallback
......@@ -16,6 +23,8 @@ import com.base.pdfviewerscannerwhite.ui.document.pdf.PdfPagerAdapter
import com.base.pdfviewerscannerwhite.ui.document.pdf.PdfPresenter
import com.base.pdfviewerscannerwhite.ui.document.pdf.PdfView
import com.base.pdfviewerscannerwhite.utils.LogEx
import java.io.File
/**
* [com.artifex.mupdf.viewer.DocumentActivity]
......@@ -25,20 +34,22 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
private val TAG = "PdfTestActivity"
private lateinit var pdfPresenter: PdfPresenter
private lateinit var adapter: PdfPagerAdapter
private lateinit var pdfPageAdapter: PdfPagerAdapter
private var core: MuPDFCore? = null
private lateinit var readerView: ReaderView
private lateinit var readerView: ReaderViewVertical
private var searchTask: SearchTask? = null
//居然是这样实现的
private var mFlatOutline: ArrayList<OutlineActivity.Item>? = null
private var mLayoutW = 440
private var mLayoutH = 660
private var mLayoutW = 600
private var mLayoutH = 800
private var mDisplayDPI = 0
private val mLayoutEM = 10
private var uiMode = UI_MODE_NORMAL
override val binding: ActivityPdfTestBinding by lazy {
ActivityPdfTestBinding.inflate(layoutInflater)
......@@ -58,6 +69,8 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
uri = intent.extras?.getString("uri") ?: ""
path = intent.extras?.getString("path") ?: ""
size = intent.extras?.getLong("size") ?: -1L
val file = File(path)
binding.tvPdfName.text = file.name
initAdapter()
......@@ -70,21 +83,21 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
initReaderView()
pdfPresenter.iniPdfPage(path)
}
}
private fun initAdapter() {
adapter = PdfPagerAdapter(path)
adapter.clickAction = { pageIndex ->
pdfPageAdapter = PdfPagerAdapter(path)
pdfPageAdapter.clickAction = { pageIndex ->
readerView.displayedViewIndex = pageIndex
}
binding.rvPager.adapter = adapter
binding.rvPager.adapter = pdfPageAdapter
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
LogEx.logDebug(TAG, "onBackPressedDispatcher ${binding.editSearch.isVisible}")
if (binding.editSearch.isVisible) {
noSearchUI()
} else {
......@@ -109,6 +122,22 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
}
false
}
binding.ivBianji.setOnClickListener {
changeEditSaveUI()
}
binding.llHighlight.setOnClickListener {
changeEditSelectUI(it)
}
binding.llGlideLine.setOnClickListener {
changeEditSelectUI(it)
}
binding.llStrikethrough.setOnClickListener {
changeEditSelectUI(it)
}
binding.llPaintingBrush.setOnClickListener {
changeEditSelectUI(it)
}
}
private fun initSearchTask() {
......@@ -135,24 +164,6 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
searchTask?.go(binding.editSearch.text.toString(), direction, displayPage, searchPage)
}
fun noSearchUI() {
binding.editSearch.visibility = View.GONE
binding.tvPdfName.visibility = View.VISIBLE
binding.ivXuanzhuan.visibility = View.VISIBLE
binding.ivMore.visibility = View.VISIBLE
}
private fun searchUi() {
binding.tvPdfName.visibility = View.GONE
binding.ivXuanzhuan.visibility = View.GONE
binding.ivMore.visibility = View.GONE
binding.editSearch.visibility = View.VISIBLE
binding.editSearch.requestFocus()
}
/**
* need size
......@@ -163,50 +174,148 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
@SuppressLint("SetTextI18n")
private fun initReaderView() {
binding.tvPageCount.text = "1/${core?.countPages()}"
readerView = object : ReaderView(this) {
readerView = object : ReaderViewVertical(this) {
@SuppressLint("SetTextI18n")
override fun onMoveToChild(i: Int) {
LogEx.logDebug(TAG, "onMoveToChild $i")
binding.tvPageCount.text = "${i + 1}/${core?.countPages()}"
pdfPageAdapter.changeSelectPager(i)
super.onMoveToChild(i)
}
override fun onTapMainDocArea() {
super.onTapMainDocArea()
if (isShowTopBottomLayout) {
hideTopBottomLayout()
} else {
showTopBottomLayout()
}
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
LogEx.logDebug(TAG, "w$w h=$h oldw=$oldw oldh=$oldh")
//文档内容能够根据不同的屏幕尺寸或布局自动重新排列的特性
if (core?.isReflowable == true) {
mLayoutW = w * 72 / mDisplayDPI
mLayoutH = h * 72 / mDisplayDPI
relayoutDocument()
} else {
refresh()
}
// if (core?.isReflowable == true) {
// mLayoutW = w * 72 / mDisplayDPI
// mLayoutH = h * 72 / mDisplayDPI
// LogEx.logDebug(TAG, "changeLayout mLayoutW=$mLayoutW mLayoutH=$mLayoutH")
// relayoutDocument()
// } else {
// LogEx.logDebug(TAG, "refresh")
// refresh()
// }
}
}
readerView.adapter = PageAdapter(this, core)
val cc = PageAdapter(this, core)
readerView.adapter = cc
binding.rl.addView(readerView)
}
fun relayoutDocument() {
if (core != null) {
val loc = core?.layout(readerView.mCurrent, mLayoutW, mLayoutH, mLayoutEM) ?: 0
mFlatOutline = null
readerView.mHistory?.clear()
readerView.refresh()
readerView.displayedViewIndex = loc
private var isShowTopBottomLayout = true
private fun hideTopBottomLayout() {
if (isShowTopBottomLayout) {
isShowTopBottomLayout = false
hideKeyboard()
val topAnim: Animation = TranslateAnimation(0f, 0f, 0f, -binding.vAnimatorTop.height.toFloat())
topAnim.setDuration(200)
topAnim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
binding.vAnimatorTop.visibility = View.GONE
}
})
binding.vAnimatorTop.startAnimation(topAnim)
val bottomAnim: Animation = TranslateAnimation(0f, 0f, 0f, binding.vAnimatorBottom.height.toFloat())
bottomAnim.duration = 200
bottomAnim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
binding.vAnimatorBottom.visibility = View.GONE
}
})
binding.vAnimatorBottom.startAnimation(bottomAnim)
bianJiScaleXiao()
}
}
private fun showTopBottomLayout() {
if (!isShowTopBottomLayout) {
isShowTopBottomLayout = true
val topAnim: Animation = TranslateAnimation(0f, 0f, -binding.vAnimatorTop.height.toFloat(), 0f)
topAnim.setDuration(200)
topAnim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {
binding.vAnimatorTop.visibility = View.VISIBLE
}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
}
})
binding.vAnimatorTop.startAnimation(topAnim)
val bottomAnim: Animation = TranslateAnimation(0f, 0f, binding.vAnimatorBottom.height.toFloat(), 0f)
bottomAnim.duration = 200
bottomAnim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {
binding.vAnimatorBottom.visibility = View.VISIBLE
}
override fun onAnimationRepeat(animation: Animation) {}
override fun onAnimationEnd(animation: Animation) {
}
})
binding.vAnimatorBottom.startAnimation(bottomAnim)
bianJiScaleDa()
}
}
private fun bianJiScaleDa() {
val scaleXAnimator = ObjectAnimator.ofFloat(binding.ivBianji, "scaleX", 0f, 1.0f)
scaleXAnimator.duration = 200
val scaleYAnimator = ObjectAnimator.ofFloat(binding.ivBianji, "scaleY", 0f, 1.0f)
scaleYAnimator.duration = 200
val animatorSet = AnimatorSet()
animatorSet.playTogether(scaleXAnimator, scaleYAnimator)
animatorSet.start()
}
private fun bianJiScaleXiao(endAction: (() -> Unit)? = null) {
val scaleXAnimator = ObjectAnimator.ofFloat(binding.ivBianji, "scaleX", 1.0f, 0f)
scaleXAnimator.duration = 200
val scaleYAnimator = ObjectAnimator.ofFloat(binding.ivBianji, "scaleY", 1.0f, 0f)
scaleYAnimator.duration = 200
val animatorSet = AnimatorSet()
animatorSet.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) = Unit
override fun onAnimationEnd(animation: Animator) {
endAction?.invoke()
}
override fun onAnimationCancel(animation: Animator) = Unit
override fun onAnimationRepeat(animation: Animator) = Unit
})
animatorSet.playTogether(scaleXAnimator, scaleYAnimator)
animatorSet.start()
}
override fun onPause() {
super.onPause()
searchTask?.stop()
......@@ -217,7 +326,86 @@ class PdfTestActivity : BaseActivity<ActivityPdfTestBinding>(), PdfView {
}
override fun initPdfPageRv(items: List<PdfPageBean>) {
adapter.submitList(items)
pdfPageAdapter.submitList(items)
pdfPageAdapter.changeSelectPager(0)
}
fun noSearchUI() {
binding.editSearch.visibility = View.GONE
binding.tvPdfName.visibility = View.VISIBLE
binding.ivXuanzhuan.visibility = View.VISIBLE
binding.ivMore.visibility = View.VISIBLE
binding.rvPager.visibility = View.VISIBLE
}
/**
* 搜索模式
*/
private fun searchUi() {
bianJiScaleXiao{
binding.tvPdfName.visibility = View.INVISIBLE
binding.ivXuanzhuan.visibility = View.GONE
binding.ivMore.visibility = View.GONE
binding.rvPager.visibility = View.GONE
binding.editSearch.visibility = View.VISIBLE
binding.editSearch.requestFocus()
}
}
/**
* 编辑保存模式
*/
private fun changeEditSaveUI() {
uiMode = UI_MODE_EDITE_SAVE
bianJiScaleXiao {
binding.rvPager.visibility = View.VISIBLE
binding.clOperation.visibility = View.VISIBLE
val file = File(path)
binding.tvPdfName.text = file.name
binding.ivXuanzhuan.visibility = View.INVISIBLE
binding.ivSearch.visibility = View.INVISIBLE
binding.ivMore.visibility = View.INVISIBLE
binding.tvBtnSave.visibility = View.VISIBLE
}
}
/**
* 编辑选择模式
*/
private fun changeEditSelectUI(view: View) {
uiMode = UI_MODE_EDITE_SELECT
binding.rvPager.visibility = View.GONE
if (binding.llHighlight == view) {
binding.llHighlight.setBackgroundColor(Color.parseColor("#525252"))
} else {
binding.llHighlight.setBackgroundColor(Color.TRANSPARENT)
}
if (binding.llGlideLine == view) {
binding.llGlideLine.setBackgroundColor(Color.parseColor("#525252"))
} else {
binding.llGlideLine.setBackgroundColor(Color.TRANSPARENT)
}
if (binding.llStrikethrough == view) {
binding.llStrikethrough.setBackgroundColor(Color.parseColor("#525252"))
} else {
binding.llStrikethrough.setBackgroundColor(Color.TRANSPARENT)
}
if (binding.llPaintingBrush == view) {
binding.llPaintingBrush.setBackgroundColor(Color.parseColor("#525252"))
} else {
binding.llPaintingBrush.setBackgroundColor(Color.TRANSPARENT)
}
}
companion object {
const val UI_MODE_NORMAL = 0
const val UI_MODE_EDITE_SAVE = 1
const val UI_MODE_EDITE_SELECT = 2
}
}
\ No newline at end of file
package com.artifex.mupdf.viewer;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.WindowManager;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.Scroller;
import com.artifex.mupdf.fitz.Link;
import com.base.pdfviewerscannerwhite.utils.LogEx;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Stack;
public class ReaderViewVertical
extends AdapterView<Adapter>
implements GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, Runnable {
private String TAG = "ReaderViewVertical";
private Context mContext;
private boolean mLinksEnabled = false;
private boolean tapDisabled = false;
private int tapPageMargin;
private static final int MOVING_DIAGONALLY = 0;
private static final int MOVING_LEFT = 1;
private static final int MOVING_RIGHT = 2;
private static final int MOVING_UP = 3;
private static final int MOVING_DOWN = 4;
private static final int FLING_MARGIN = 100;
private static final int GAP = 20;
private static final float MIN_SCALE = 1.0f;
private static final float MAX_SCALE = 64.0f;
private static final boolean HORIZONTAL_SCROLLING = true;
private PageAdapter mAdapter;
protected int mCurrent; // Adapter's index for the current view
private boolean mResetLayout;
private final SparseArray<View>
mChildViews = new SparseArray<View>(3);
// Shadows the children of the adapter view
// but with more sensible indexing
private final LinkedList<View>
mViewCache = new LinkedList<View>();
private boolean mUserInteracting; // Whether the user is interacting
private boolean mScaling; // Whether the user is currently pinch zooming
private float mScale = 1.0f;
private int mXScroll; // Scroll amounts recorded from events.
private int mYScroll; // and then accounted for in onLayout
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private Scroller mScroller;
private Stepper mStepper;
private int mScrollerLastX;
private int mScrollerLastY;
private float mLastScaleFocusX;
private float mLastScaleFocusY;
protected Stack<Integer> mHistory;
static abstract class ViewMapper {
abstract void applyToView(View view);
}
public ReaderViewVertical(Context context) {
super(context);
setup(context);
}
public ReaderViewVertical(Context context, AttributeSet attrs) {
super(context, attrs);
setup(context);
}
public ReaderViewVertical(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup(context);
}
private void setup(Context context) {
mContext = context;
mGestureDetector = new GestureDetector(context, this);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mScroller = new Scroller(context);
mStepper = new Stepper(this, this);
mHistory = new Stack<Integer>();
// Get the screen size etc to customise tap margins.
// We calculate the size of 1 inch of the screen for tapping.
// On some devices the dpi values returned are wrong, so we
// sanity check it: we first restrict it so that we are never
// less than 100 pixels (the smallest Android device screen
// dimension I've seen is 480 pixels or so). Then we check
// to ensure we are never more than 1/5 of the screen width.
DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(dm);
tapPageMargin = (int) dm.xdpi;
if (tapPageMargin < 100)
tapPageMargin = 100;
if (tapPageMargin > dm.widthPixels / 5)
tapPageMargin = dm.widthPixels / 5;
}
public boolean popHistory() {
if (mHistory.empty())
return false;
setDisplayedViewIndex(mHistory.pop());
return true;
}
public void pushHistory() {
mHistory.push(mCurrent);
}
public int getDisplayedViewIndex() {
return mCurrent;
}
public void setDisplayedViewIndex(int i) {
if (0 <= i && i < mAdapter.getCount()) {
onMoveOffChild(mCurrent);
mCurrent = i;
onMoveToChild(i);
mResetLayout = true;
requestLayout();
}
}
public void moveToNext() {
View v = mChildViews.get(mCurrent + 1);
if (v != null)
slideViewOntoScreen(v);
}
public void moveToPrevious() {
View v = mChildViews.get(mCurrent - 1);
if (v != null)
slideViewOntoScreen(v);
}
// When advancing down the page, we want to advance by about
// 90% of a screenful. But we'd be happy to advance by between
// 80% and 95% if it means we hit the bottom in a whole number
// of steps.
private int smartAdvanceAmount(int screenHeight, int max) {
int advance = (int) (screenHeight * 0.9 + 0.5);
int leftOver = max % advance;
int steps = max / advance;
if (leftOver == 0) {
// We'll make it exactly. No adjustment
} else if ((float) leftOver / steps <= screenHeight * 0.05) {
// We can adjust up by less than 5% to make it exact.
advance += (int) ((float) leftOver / steps + 0.5);
} else {
int overshoot = advance - leftOver;
if ((float) overshoot / steps <= screenHeight * 0.1) {
// We can adjust down by less than 10% to make it exact.
advance -= (int) ((float) overshoot / steps + 0.5);
}
}
if (advance > max)
advance = max;
return advance;
}
public void smartMoveForwards() {
View v = mChildViews.get(mCurrent);
if (v == null)
return;
// The following code works in terms of where the screen is on the views;
// so for example, if the currentView is at (-100,-100), the visible
// region would be at (100,100). If the previous page was (2000, 3000) in
// size, the visible region of the previous page might be (2100 + GAP, 100)
// (i.e. off the previous page). This is different to the way the rest of
// the code in this file is written, but it's easier for me to think about.
// At some point we may refactor this to fit better with the rest of the
// code.
// screenWidth/Height are the actual width/height of the screen. e.g. 480/800
int screenWidth = getWidth();
int screenHeight = getHeight();
// We might be mid scroll; we want to calculate where we scroll to based on
// where this scroll would end, not where we are now (to allow for people
// bashing 'forwards' very fast.
int remainingX = mScroller.getFinalX() - mScroller.getCurrX();
int remainingY = mScroller.getFinalY() - mScroller.getCurrY();
// right/bottom is in terms of pixels within the scaled document; e.g. 1000
int top = -(v.getTop() + mYScroll + remainingY);
int right = screenWidth - (v.getLeft() + mXScroll + remainingX);
int bottom = screenHeight + top;
// docWidth/Height are the width/height of the scaled document e.g. 2000x3000
int docWidth = v.getMeasuredWidth();
int docHeight = v.getMeasuredHeight();
int xOffset, yOffset;
if (bottom >= docHeight) {
// We are flush with the bottom. Advance to next column.
if (right + screenWidth > docWidth) {
// No room for another column - go to next page
View nv = mChildViews.get(mCurrent + 1);
if (nv == null) // No page to advance to
return;
int nextTop = -(nv.getTop() + mYScroll + remainingY);
int nextLeft = -(nv.getLeft() + mXScroll + remainingX);
int nextDocWidth = nv.getMeasuredWidth();
int nextDocHeight = nv.getMeasuredHeight();
// Allow for the next page maybe being shorter than the screen is high
yOffset = (nextDocHeight < screenHeight ? ((nextDocHeight - screenHeight) >> 1) : 0);
if (nextDocWidth < screenWidth) {
// Next page is too narrow to fill the screen. Scroll to the top, centred.
xOffset = (nextDocWidth - screenWidth) >> 1;
} else {
// Reset X back to the left hand column
xOffset = right % screenWidth;
// Adjust in case the previous page is less wide
if (xOffset + screenWidth > nextDocWidth)
xOffset = nextDocWidth - screenWidth;
}
xOffset -= nextLeft;
yOffset -= nextTop;
} else {
// Move to top of next column
xOffset = screenWidth;
yOffset = screenHeight - bottom;
}
} else {
// Advance by 90% of the screen height downwards (in case lines are partially cut off)
xOffset = 0;
yOffset = smartAdvanceAmount(screenHeight, docHeight - bottom);
}
mScrollerLastX = mScrollerLastY = 0;
mScroller.startScroll(0, 0, remainingX - xOffset, remainingY - yOffset, 400);
mStepper.prod();
}
public void smartMoveBackwards() {
View v = mChildViews.get(mCurrent);
if (v == null)
return;
// The following code works in terms of where the screen is on the views;
// so for example, if the currentView is at (-100,-100), the visible
// region would be at (100,100). If the previous page was (2000, 3000) in
// size, the visible region of the previous page might be (2100 + GAP, 100)
// (i.e. off the previous page). This is different to the way the rest of
// the code in this file is written, but it's easier for me to think about.
// At some point we may refactor this to fit better with the rest of the
// code.
// screenWidth/Height are the actual width/height of the screen. e.g. 480/800
int screenWidth = getWidth();
int screenHeight = getHeight();
// We might be mid scroll; we want to calculate where we scroll to based on
// where this scroll would end, not where we are now (to allow for people
// bashing 'forwards' very fast.
int remainingX = mScroller.getFinalX() - mScroller.getCurrX();
int remainingY = mScroller.getFinalY() - mScroller.getCurrY();
// left/top is in terms of pixels within the scaled document; e.g. 1000
int left = -(v.getLeft() + mXScroll + remainingX);
int top = -(v.getTop() + mYScroll + remainingY);
// docWidth/Height are the width/height of the scaled document e.g. 2000x3000
int docHeight = v.getMeasuredHeight();
int xOffset, yOffset;
if (top <= 0) {
// We are flush with the top. Step back to previous column.
if (left < screenWidth) {
/* No room for previous column - go to previous page */
View pv = mChildViews.get(mCurrent - 1);
if (pv == null) /* No page to advance to */
return;
int prevDocWidth = pv.getMeasuredWidth();
int prevDocHeight = pv.getMeasuredHeight();
// Allow for the next page maybe being shorter than the screen is high
yOffset = (prevDocHeight < screenHeight ? ((prevDocHeight - screenHeight) >> 1) : 0);
int prevLeft = -(pv.getLeft() + mXScroll);
int prevTop = -(pv.getTop() + mYScroll);
if (prevDocWidth < screenWidth) {
// Previous page is too narrow to fill the screen. Scroll to the bottom, centred.
xOffset = (prevDocWidth - screenWidth) >> 1;
} else {
// Reset X back to the right hand column
xOffset = (left > 0 ? left % screenWidth : 0);
if (xOffset + screenWidth > prevDocWidth)
xOffset = prevDocWidth - screenWidth;
while (xOffset + screenWidth * 2 < prevDocWidth)
xOffset += screenWidth;
}
xOffset -= prevLeft;
yOffset -= prevTop - prevDocHeight + screenHeight;
} else {
// Move to bottom of previous column
xOffset = -screenWidth;
yOffset = docHeight - screenHeight + top;
}
} else {
// Retreat by 90% of the screen height downwards (in case lines are partially cut off)
xOffset = 0;
yOffset = -smartAdvanceAmount(screenHeight, top);
}
mScrollerLastX = mScrollerLastY = 0;
mScroller.startScroll(0, 0, remainingX - xOffset, remainingY - yOffset, 400);
mStepper.prod();
}
public void resetupChildren() {
for (int i = 0; i < mChildViews.size(); i++)
onChildSetup(mChildViews.keyAt(i), mChildViews.valueAt(i));
}
public void applyToChildren(ViewMapper mapper) {
for (int i = 0; i < mChildViews.size(); i++)
mapper.applyToView(mChildViews.valueAt(i));
}
public void refresh() {
mResetLayout = true;
mScale = 1.0f;
mXScroll = mYScroll = 0;
/* All page views need recreating since both page and screen has changed size,
* invalidating both sizes and bitmaps. */
mAdapter.refresh();
int numChildren = mChildViews.size();
for (int i = 0; i < mChildViews.size(); i++) {
View v = mChildViews.valueAt(i);
onNotInUse(v);
removeViewInLayout(v);
}
mChildViews.clear();
mViewCache.clear();
requestLayout();
}
public View getView(int i) {
return mChildViews.get(i);
}
public View getDisplayedView() {
return mChildViews.get(mCurrent);
}
public void run() {
if (!mScroller.isFinished()) {
mScroller.computeScrollOffset();
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
mXScroll += x - mScrollerLastX;
mYScroll += y - mScrollerLastY;
mScrollerLastX = x;
mScrollerLastY = y;
requestLayout();
mStepper.prod();
} else if (!mUserInteracting) {
// End of an inertial scroll and the user is not interacting.
// The layout is stable
View v = mChildViews.get(mCurrent);
if (v != null)
postSettle(v);
}
}
public boolean onDown(MotionEvent arg0) {
mScroller.forceFinished(true);
return true;
}
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_LEFT:
if (HORIZONTAL_SCROLLING && bounds.left >= 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_UP:
// if (!HORIZONTAL_SCROLLING && bounds.top >= 0) {
// // Fling off to the top bring next view onto screen
// View vl = mChildViews.get(mCurrent + 1);
//
// if (vl != null) {
// slideViewOntoScreen(vl);
// return true;
// }
// }
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_RIGHT:
if (HORIZONTAL_SCROLLING && bounds.right <= 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;
case MOVING_DOWN:
// if (!HORIZONTAL_SCROLLING && bounds.bottom <= 0) {
// // Fling off to the bottom bring previous view onto screen
// View vr = mChildViews.get(mCurrent - 1);
//
// if (vr != null) {
// slideViewOntoScreen(vr);
// return true;
// }
// }
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;
}
public void onLongPress(MotionEvent e) {
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
LogEx.INSTANCE.logDebug(TAG, "onScroll", false);
PageView pageView = (PageView) getDisplayedView();
if (!tapDisabled)
onDocMotion();
if (!mScaling) {
mXScroll -= distanceX;
mYScroll -= distanceY;
requestLayout();
}
return true;
}
public void onShowPress(MotionEvent e) {
}
public boolean onScale(ScaleGestureDetector detector) {
float previousScale = mScale;
mScale = Math.min(Math.max(mScale * detector.getScaleFactor(), MIN_SCALE), MAX_SCALE);
{
float factor = mScale / previousScale;
View v = mChildViews.get(mCurrent);
if (v != null) {
float currentFocusX = detector.getFocusX();
float currentFocusY = detector.getFocusY();
// Work out the focus point relative to the view top left
int viewFocusX = (int) currentFocusX - (v.getLeft() + mXScroll);
int viewFocusY = (int) currentFocusY - (v.getTop() + mYScroll);
// Scroll to maintain the focus point
mXScroll += viewFocusX - viewFocusX * factor;
mYScroll += viewFocusY - viewFocusY * factor;
if (mLastScaleFocusX >= 0)
mXScroll += currentFocusX - mLastScaleFocusX;
if (mLastScaleFocusY >= 0)
mYScroll += currentFocusY - mLastScaleFocusY;
mLastScaleFocusX = currentFocusX;
mLastScaleFocusY = currentFocusY;
requestLayout();
}
}
return true;
}
public boolean onScaleBegin(ScaleGestureDetector detector) {
tapDisabled = true;
mScaling = true;
// Ignore any scroll amounts yet to be accounted for: the
// screen is not showing the effect of them, so they can
// only confuse the user
mXScroll = mYScroll = 0;
mLastScaleFocusX = mLastScaleFocusY = -1;
return true;
}
public void onScaleEnd(ScaleGestureDetector detector) {
mScaling = false;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if ((event.getAction() & event.getActionMasked()) == MotionEvent.ACTION_DOWN) {
tapDisabled = false;
}
mScaleGestureDetector.onTouchEvent(event);
mGestureDetector.onTouchEvent(event);
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
mUserInteracting = true;
}
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
mUserInteracting = false;
View v = mChildViews.get(mCurrent);
if (v != null) {
if (mScroller.isFinished()) {
// If, at the end of user interaction, there is no
// current inertial scroll in operation then animate
// the view onto screen if necessary
slideViewOntoScreen(v);
}
if (mScroller.isFinished()) {
// If still there is no inertial scroll in operation
// then the layout is stable
postSettle(v);
}
}
}
requestLayout();
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int n = getChildCount();
for (int i = 0; i < n; i++)
measureView(getChildAt(i));
}
// @Override
// protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// super.onLayout(changed, left, top, right, bottom);
//
// try {
// onLayout2(changed, left, top, right, bottom);
// }
// catch (OutOfMemoryError e) {
// System.out.println("Out of memory during layout");
// }
// }
//https://stackoverflow.com/questions/33333069/mupdf-android-library-vertical-scroll
@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();
@SuppressLint("DrawAllocation")
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 (mResetLayout) {
mResetLayout = 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();
}
private void onLayout2(boolean changed, int left, int top, int right,
int 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) {
boolean move;
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 (HORIZONTAL_SCROLLING)
move = cv.getLeft() + cv.getMeasuredWidth() + cvOffset.x + GAP / 2 + mXScroll < getWidth() / 2;
else
move = cv.getTop() + cv.getMeasuredHeight() + cvOffset.y + GAP / 2 + mYScroll < getHeight() / 2;
if (move && 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 (HORIZONTAL_SCROLLING)
move = cv.getLeft() - cvOffset.x - GAP / 2 + mXScroll >= getWidth() / 2;
else
move = cv.getTop() - cvOffset.y - GAP / 2 + mYScroll >= getHeight() / 2;
if (move && 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();
// 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 (HORIZONTAL_SCROLLING && cv.getMeasuredHeight() <= getHeight()) {
// 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;
} else if (!HORIZONTAL_SCROLLING && cv.getMeasuredWidth() <= getWidth()) {
// 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);
if (HORIZONTAL_SCROLLING) {
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);
} else {
int gap = leftOffset.y + GAP + cvOffset.y;
lv.layout((cvLeft + cvRight - lv.getMeasuredWidth()) / 2,
cvTop - lv.getMeasuredHeight() - gap,
(cvLeft + cvRight + lv.getMeasuredWidth()) / 2,
cvTop - gap);
}
}
if (mCurrent + 1 < mAdapter.getCount()) {
View rv = getOrCreateChild(mCurrent + 1);
Point rightOffset = subScreenSizeOffset(rv);
if (HORIZONTAL_SCROLLING) {
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);
} else {
int gap = cvOffset.y + GAP + rightOffset.y;
rv.layout((cvLeft + cvRight - rv.getMeasuredWidth()) / 2,
cvBottom + gap,
(cvLeft + cvRight + rv.getMeasuredWidth()) / 2,
cvBottom + gap + rv.getMeasuredHeight());
}
}
invalidate();
}
@Override
public Adapter getAdapter() {
return mAdapter;
}
@Override
public View getSelectedView() {
return null;
}
@Override
public void setAdapter(Adapter adapter) {
if (mAdapter != null && mAdapter != adapter)
mAdapter.releaseBitmaps();
mAdapter = (PageAdapter) adapter;
requestLayout();
}
@Override
public void setSelection(int arg0) {
throw new UnsupportedOperationException(getContext().getString(R.string.not_supported));
}
private View getCached() {
if (mViewCache.size() == 0)
return null;
else
return mViewCache.removeFirst();
}
private View getOrCreateChild(int i) {
View v = mChildViews.get(i);
if (v == null) {
v = mAdapter.getView(i, getCached(), this);
addAndMeasureChild(i, v);
onChildSetup(i, v);
}
return v;
}
private void addAndMeasureChild(int i, View v) {
LayoutParams params = v.getLayoutParams();
if (params == null) {
params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
addViewInLayout(v, 0, params, true);
mChildViews.append(i, v); // Record the view against its adapter index
measureView(v);
}
private void measureView(View v) {
// See what size the view wants to be
v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
// Work out a scale that will fit it to this view
float scale = Math.min((float) getWidth() / (float) v.getMeasuredWidth(),
(float) getHeight() / (float) v.getMeasuredHeight());
// Use the fitting values scaled by our current scale factor
v.measure(MeasureSpec.EXACTLY | (int) (v.getMeasuredWidth() * scale * mScale),
MeasureSpec.EXACTLY | (int) (v.getMeasuredHeight() * scale * mScale));
}
private Rect getScrollBounds(int left, int top, int right, int bottom) {
int xmin = getWidth() - right;
int xmax = -left;
int ymin = getHeight() - bottom;
int ymax = -top;
// In either dimension, if view smaller than screen then
// constrain it to be central
if (xmin > xmax) xmin = xmax = (xmin + xmax) / 2;
if (ymin > ymax) ymin = ymax = (ymin + ymax) / 2;
return new Rect(xmin, ymin, xmax, ymax);
}
private Rect getScrollBounds(View v) {
// There can be scroll amounts not yet accounted for in
// onLayout, so add mXScroll and mYScroll to the current
// positions when calculating the bounds.
return getScrollBounds(v.getLeft() + mXScroll,
v.getTop() + mYScroll,
v.getLeft() + v.getMeasuredWidth() + mXScroll,
v.getTop() + v.getMeasuredHeight() + mYScroll);
}
private Point getCorrection(Rect bounds) {
return new Point(Math.min(Math.max(0, bounds.left), bounds.right),
Math.min(Math.max(0, bounds.top), bounds.bottom));
}
private void postSettle(final View v) {
// onSettle and onUnsettle are posted so that the calls
// won't be executed until after the system has performed
// layout.
post(new Runnable() {
public void run() {
onSettle(v);
}
});
}
private void postUnsettle(final View v) {
post(new Runnable() {
public void run() {
onUnsettle(v);
}
});
}
private void slideViewOntoScreen(View v) {
Point corr = getCorrection(getScrollBounds(v));
if (corr.x != 0 || corr.y != 0) {
mScrollerLastX = mScrollerLastY = 0;
mScroller.startScroll(0, 0, corr.x, corr.y, 400);
mStepper.prod();
}
}
private Point subScreenSizeOffset(View v) {
return new Point(Math.max((getWidth() - v.getMeasuredWidth()) / 2, 0),
Math.max((getHeight() - v.getMeasuredHeight()) / 2, 0));
}
private static int directionOfTravel(float vx, float vy) {
if (Math.abs(vx) > 2 * Math.abs(vy))
return (vx > 0) ? MOVING_RIGHT : MOVING_LEFT;
else if (Math.abs(vy) > 2 * Math.abs(vx))
return (vy > 0) ? MOVING_DOWN : MOVING_UP;
else
return MOVING_DIAGONALLY;
}
private static boolean withinBoundsInDirectionOfTravel(Rect bounds, float vx, float vy) {
switch (directionOfTravel(vx, vy)) {
case MOVING_DIAGONALLY:
return bounds.contains(0, 0);
case MOVING_LEFT:
return bounds.left <= 0;
case MOVING_RIGHT:
return bounds.right >= 0;
case MOVING_UP:
return bounds.top <= 0;
case MOVING_DOWN:
return bounds.bottom >= 0;
default:
throw new NoSuchElementException();
}
}
protected void onTapMainDocArea() {
}
protected void onDocMotion() {
}
public void setLinksEnabled(boolean b) {
mLinksEnabled = b;
resetupChildren();
invalidate();
}
public boolean onSingleTapUp(MotionEvent e) {
Link link = null;
if (!tapDisabled) {
PageView pageView = (PageView) getDisplayedView();
if (mLinksEnabled && pageView != null) {
int page = pageView.hitLink(e.getX(), e.getY());
if (page > 0) {
pushHistory();
setDisplayedViewIndex(page);
} else {
onTapMainDocArea();
}
} else if (e.getX() < tapPageMargin) {
smartMoveBackwards();
} else if (e.getX() > super.getWidth() - tapPageMargin) {
smartMoveForwards();
} else if (e.getY() < tapPageMargin) {
smartMoveBackwards();
} else if (e.getY() > super.getHeight() - tapPageMargin) {
smartMoveForwards();
} else {
onTapMainDocArea();
}
}
return true;
}
protected void onChildSetup(int i, View v) {
if (SearchTaskResult.get() != null
&& SearchTaskResult.get().pageNumber == i)
((PageView) v).setSearchBoxes(SearchTaskResult.get().searchBoxes);
else
((PageView) v).setSearchBoxes(null);
((PageView) v).setLinkHighlighting(mLinksEnabled);
}
protected void onMoveToChild(int i) {
if (SearchTaskResult.get() != null
&& SearchTaskResult.get().pageNumber != i) {
SearchTaskResult.set(null);
resetupChildren();
}
}
protected void onMoveOffChild(int i) {
}
protected void onSettle(View v) {
// When the layout has settled ask the page to render
// in HQ
((PageView) v).updateHq(false);
}
protected void onUnsettle(View v) {
// When something changes making the previous settled view
// no longer appropriate, tell the page to remove HQ
((PageView) v).removeHq();
}
protected void onNotInUse(View v) {
((PageView) v).releaseResources();
}
}
......@@ -7,7 +7,7 @@ object LogEx {
val isOpen = true
val filterTAG = arrayOf(
"",
// "MediaStoreUtils",
"MediaStoreUtils",
)
fun logDebug(tag: String, content: String, isMust: Boolean = false) {
......
......@@ -8,10 +8,21 @@
android:background="@color/white"
tools:context="com.artifex.mupdf.viewer.PdfTestActivity">
<RelativeLayout
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp">
</RelativeLayout>
<ViewAnimator
android:id="@+id/v_animator_top"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@color/white"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
......@@ -40,14 +51,16 @@
</FrameLayout>
<TextView
android:id="@+id/tv_pdf_name"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="19sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/iv_xuanzhuan"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText"
......@@ -105,18 +118,179 @@
app:layout_constraintTop_toTopOf="parent"
tools:ignore="Autofill,HardcodedText,TextFields" />
<TextView
android:id="@+id/tv_btn_save"
android:layout_width="90dp"
android:layout_height="36dp"
android:background="@drawable/bg_00b8de_10"
android:gravity="center"
android:text="Save"
android:textColor="@color/white"
android:textSize="16sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/iv_xuanzhuan"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ViewAnimator>
<RelativeLayout
android:id="@+id/rl"
<ViewAnimator
android:id="@+id/v_animator_bottom"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/v_animator_bottom"
app:layout_constraintTop_toBottomOf="@id/v_animator_top">
android:layout_height="wrap_content"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:ignore="UselessParent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_operation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/v_animator_bottom">
<LinearLayout
android:id="@+id/ll_highlight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@id/ll_glide_line"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@mipmap/highlight"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:text="Highlight"
android:textColor="#232323"
android:textSize="12sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_glide_line"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@id/ll_strikethrough"
app:layout_constraintStart_toEndOf="@id/ll_highlight"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@mipmap/glideline"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:text="Glide Line"
android:textColor="#232323"
android:textSize="12sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_strikethrough"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toStartOf="@id/ll_painting_brush"
app:layout_constraintStart_toEndOf="@id/ll_glide_line"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@mipmap/strike"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:text="Strikethrough"
android:textColor="#232323"
android:textSize="12sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_painting_brush"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ll_strikethrough"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@mipmap/strike"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:text="Strikethrough"
android:textColor="#232323"
android:textSize="12sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_pager"
android:layout_width="match_parent"
android:layout_height="88dp"
android:orientation="horizontal"
android:paddingHorizontal="4dp"
android:paddingTop="5dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/pdfview"
tools:listitem="@layout/item_pdf_pager" />
</LinearLayout>
</ViewAnimator>
</RelativeLayout>
<TextView
android:id="@+id/tv_pageCount"
......@@ -131,27 +305,20 @@
android:textColor="@color/white"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/rl"
app:layout_constraintTop_toBottomOf="@id/v_animator_top"
tools:text="1/3" />
<ViewAnimator
android:id="@+id/v_animator_bottom"
android:layout_width="match_parent"
<ImageView
android:id="@+id/iv_bianji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent">
android:layout_marginEnd="15dp"
android:layout_marginBottom="108dp"
android:src="@mipmap/bianji"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="ContentDescription" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_pager"
android:layout_width="match_parent"
android:layout_height="88dp"
android:orientation="horizontal"
android:paddingHorizontal="4dp"
android:paddingTop="5dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/pdfview"
tools:listitem="@layout/item_pdf_pager" />
</ViewAnimator>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment