Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
P
PDF Viewer Scanner White ago
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
kuxulei
PDF Viewer Scanner White ago
Commits
9e5231ef
Commit
9e5231ef
authored
Sep 18, 2024
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
...
parent
c01833f8
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1599 additions
and
72 deletions
+1599
-72
PdfTestActivity.kt
...src/main/java/com/artifex/mupdf/viewer/PdfTestActivity.kt
+234
-46
ReaderViewVertical.java
...ain/java/com/artifex/mupdf/viewer/ReaderViewVertical.java
+1172
-0
LogEx.kt
...c/main/java/com/base/pdfviewerscannerwhite/utils/LogEx.kt
+1
-1
activity_pdf_test.xml
app/src/main/res/layout/activity_pdf_test.xml
+192
-25
bianji.png
app/src/main/res/mipmap-xxhdpi/bianji.png
+0
-0
glideline.png
app/src/main/res/mipmap-xxhdpi/glideline.png
+0
-0
highlight.png
app/src/main/res/mipmap-xxhdpi/highlight.png
+0
-0
painting.png
app/src/main/res/mipmap-xxhdpi/painting.png
+0
-0
strike.png
app/src/main/res/mipmap-xxhdpi/strike.png
+0
-0
No files found.
app/src/main/java/com/artifex/mupdf/viewer/PdfTestActivity.kt
View file @
9e5231ef
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
a
dapter
:
PdfPagerAdapter
private
lateinit
var
pdfPageA
dapter
:
PdfPagerAdapter
private
var
core
:
MuPDFCore
?
=
null
private
lateinit
var
readerView
:
ReaderView
private
lateinit
var
readerView
:
ReaderView
Vertical
private
var
searchTask
:
SearchTask
?
=
null
//居然是这样实现的
private
var
mFlatOutline
:
ArrayList
<
OutlineActivity
.
Item
>?
=
null
private
var
mLayoutW
=
44
0
private
var
mLayoutH
=
66
0
private
var
mLayoutW
=
60
0
private
var
mLayoutH
=
80
0
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
=
a
dapter
binding
.
rvPager
.
adapter
=
pdfPageA
dapter
}
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
:
ReaderView
Vertical
(
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
app/src/main/java/com/artifex/mupdf/viewer/ReaderViewVertical.java
0 → 100644
View file @
9e5231ef
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
();
}
}
app/src/main/java/com/base/pdfviewerscannerwhite/utils/LogEx.kt
View file @
9e5231ef
...
...
@@ -7,7 +7,7 @@ object LogEx {
val
isOpen
=
true
val
filterTAG
=
arrayOf
(
""
,
//
"MediaStoreUtils",
"MediaStoreUtils"
,
)
fun
logDebug
(
tag
:
String
,
content
:
String
,
isMust
:
Boolean
=
false
)
{
...
...
app/src/main/res/layout/activity_pdf_test.xml
View file @
9e5231ef
...
...
@@ -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_to
TopOf=
"@id/rl
"
app:layout_constraintTop_to
BottomOf=
"@id/v_animator_top
"
tools:text=
"1/3"
/>
<
ViewAnimator
android:id=
"@+id/
v_animator_bottom
"
android:layout_width=
"
match_par
ent"
<
ImageView
android:id=
"@+id/
iv_bianji
"
android:layout_width=
"
wrap_cont
ent"
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
app/src/main/res/mipmap-xxhdpi/bianji.png
0 → 100644
View file @
9e5231ef
18.4 KB
app/src/main/res/mipmap-xxhdpi/glideline.png
0 → 100644
View file @
9e5231ef
1.53 KB
app/src/main/res/mipmap-xxhdpi/highlight.png
0 → 100644
View file @
9e5231ef
2.86 KB
app/src/main/res/mipmap-xxhdpi/painting.png
0 → 100644
View file @
9e5231ef
2.56 KB
app/src/main/res/mipmap-xxhdpi/strike.png
0 → 100644
View file @
9e5231ef
1.2 KB
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment