T accessible(T accessible) {
411 | if (accessible == null) return null;
412 | if (accessible instanceof Member) {
413 | Member member = (Member) accessible;
414 | if (Modifier.isPublic(member.getModifiers())
415 | && Modifier.isPublic(member.getDeclaringClass().getModifiers())) {
416 | return accessible;
417 | }
418 | }
419 | if (!accessible.isAccessible()) accessible.setAccessible(true);
420 | return accessible;
421 | }
422 |
423 | ///////////////////////////////////////////////////////////////////////////
424 | // proxy
425 | ///////////////////////////////////////////////////////////////////////////
426 |
427 | /**
428 | * Create a proxy for the wrapped object allowing to typesafely invoke
429 | * methods on it using a custom interface.
430 | *
431 | * @param proxyType The interface type that is implemented by the proxy.
432 | * @return a proxy for the wrapped object
433 | */
434 | @SuppressWarnings("unchecked")
435 | public P proxy(final Class
proxyType) {
436 | final boolean isMap = (object instanceof Map);
437 | final InvocationHandler handler = new InvocationHandler() {
438 | @Override
439 | @SuppressWarnings("null")
440 | public Object invoke(Object proxy, Method method, Object[] args) {
441 | String name = method.getName();
442 | try {
443 | return reflect(object).method(name, args).get();
444 | } catch (ReflectException e) {
445 | if (isMap) {
446 | Map map = (Map) object;
447 | int length = (args == null ? 0 : args.length);
448 |
449 | if (length == 0 && name.startsWith("get")) {
450 | return map.get(property(name.substring(3)));
451 | } else if (length == 0 && name.startsWith("is")) {
452 | return map.get(property(name.substring(2)));
453 | } else if (length == 1 && name.startsWith("set")) {
454 | map.put(property(name.substring(3)), args[0]);
455 | return null;
456 | }
457 | }
458 | throw e;
459 | }
460 | }
461 | };
462 | return (P) Proxy.newProxyInstance(proxyType.getClassLoader(),
463 | new Class[]{proxyType},
464 | handler);
465 | }
466 |
467 | /**
468 | * Get the POJO property name of an getter/setter
469 | */
470 | private static String property(String string) {
471 | int length = string.length();
472 |
473 | if (length == 0) {
474 | return "";
475 | } else if (length == 1) {
476 | return string.toLowerCase();
477 | } else {
478 | return string.substring(0, 1).toLowerCase() + string.substring(1);
479 | }
480 | }
481 |
482 | private Class> type() {
483 | return type;
484 | }
485 |
486 | private Class> wrapper(final Class> type) {
487 | if (type == null) {
488 | return null;
489 | } else if (type.isPrimitive()) {
490 | if (boolean.class == type) {
491 | return Boolean.class;
492 | } else if (int.class == type) {
493 | return Integer.class;
494 | } else if (long.class == type) {
495 | return Long.class;
496 | } else if (short.class == type) {
497 | return Short.class;
498 | } else if (byte.class == type) {
499 | return Byte.class;
500 | } else if (double.class == type) {
501 | return Double.class;
502 | } else if (float.class == type) {
503 | return Float.class;
504 | } else if (char.class == type) {
505 | return Character.class;
506 | } else if (void.class == type) {
507 | return Void.class;
508 | }
509 | }
510 | return type;
511 | }
512 |
513 | /**
514 | * Get the result.
515 | *
516 | * @param The value type.
517 | * @return the result
518 | */
519 | @SuppressWarnings("unchecked")
520 | public T get() {
521 | return (T) object;
522 | }
523 |
524 | @Override
525 | public int hashCode() {
526 | return object.hashCode();
527 | }
528 |
529 | @Override
530 | public boolean equals(Object obj) {
531 | return obj instanceof ReflectUtils && object.equals(((ReflectUtils) obj).get());
532 | }
533 |
534 | @Override
535 | public String toString() {
536 | return object.toString();
537 | }
538 |
539 | private static class NULL {
540 | }
541 |
542 | public static class ReflectException extends RuntimeException {
543 |
544 | private static final long serialVersionUID = 858774075258496016L;
545 |
546 | public ReflectException(String message) {
547 | super(message);
548 | }
549 |
550 | public ReflectException(String message, Throwable cause) {
551 | super(message, cause);
552 | }
553 |
554 | public ReflectException(Throwable cause) {
555 | super(cause);
556 | }
557 | }
558 | }
559 |
560 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/utils/layoutmanager/MyPagerSnapHelper.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.utils.layoutmanager;
2 |
3 | import android.graphics.PointF;
4 | import android.util.DisplayMetrics;
5 | import android.view.View;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 | import androidx.recyclerview.widget.LinearSmoothScroller;
10 | import androidx.recyclerview.widget.OrientationHelper;
11 | import androidx.recyclerview.widget.RecyclerView;
12 | import androidx.recyclerview.widget.SnapHelper;
13 |
14 | import com.zjy.pdfview.utils.ReflectUtils;
15 |
16 |
17 | public class MyPagerSnapHelper extends SnapHelper {
18 |
19 | private static final String TAG = MyPagerSnapHelper.class.getSimpleName();
20 |
21 | private static final int MAX_SCROLL_ON_FLING_DURATION = 150;
22 | @Nullable
23 | private OrientationHelper mVerticalHelper;
24 | @Nullable
25 | private OrientationHelper mHorizontalHelper;
26 |
27 | @Nullable
28 | public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
29 | int[] out = new int[2];
30 | if (layoutManager.canScrollHorizontally()) {
31 | out[0] = this.distanceToCenter(layoutManager, targetView, this.getHorizontalHelper(layoutManager));
32 | } else {
33 | out[0] = 0;
34 | }
35 |
36 | if (layoutManager.canScrollVertically()) {
37 | out[1] = this.distanceToCenter(layoutManager, targetView, this.getVerticalHelper(layoutManager));
38 | } else {
39 | out[1] = 0;
40 | }
41 |
42 | return out;
43 | }
44 |
45 | @Nullable
46 | public View findSnapView(RecyclerView.LayoutManager layoutManager) {
47 | if (layoutManager.canScrollVertically()) {
48 | return this.findCenterView(layoutManager, this.getVerticalHelper(layoutManager));
49 | } else {
50 | return layoutManager.canScrollHorizontally() ? this.findCenterView(layoutManager, this.getHorizontalHelper(layoutManager)) : null;
51 | }
52 | }
53 |
54 | public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
55 | int itemCount = layoutManager.getItemCount();
56 | if (itemCount == 0) {
57 | return -1;
58 | } else {
59 | View mStartMostChildView = null;
60 | if (layoutManager.canScrollVertically()) {
61 | mStartMostChildView = this.findStartView(layoutManager, this.getVerticalHelper(layoutManager));
62 | } else if (layoutManager.canScrollHorizontally()) {
63 | mStartMostChildView = this.findStartView(layoutManager, this.getHorizontalHelper(layoutManager));
64 | }
65 |
66 | if (mStartMostChildView == null) {
67 | return -1;
68 | } else {
69 | int centerPosition = layoutManager.getPosition(mStartMostChildView);
70 | if (centerPosition == -1) {
71 | return -1;
72 | } else {
73 | if (Math.abs(velocityY) < 500) return centerPosition;
74 |
75 | boolean forwardDirection;
76 | if (layoutManager.canScrollHorizontally()) {
77 | forwardDirection = velocityX > 0;
78 | } else {
79 | forwardDirection = velocityY > 0;
80 | }
81 |
82 | boolean reverseLayout = false;
83 | if (layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider) {
84 | RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager;
85 | PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
86 | if (vectorForEnd != null) {
87 | reverseLayout = vectorForEnd.x < 0.0F || vectorForEnd.y < 0.0F;
88 | }
89 | }
90 |
91 | return reverseLayout ? (forwardDirection ? centerPosition - 1 : centerPosition) : (forwardDirection ? centerPosition + 1 : centerPosition);
92 | }
93 | }
94 | }
95 | }
96 |
97 | protected LinearSmoothScroller createSnapScroller(RecyclerView.LayoutManager layoutManager) {
98 | final RecyclerView mRecyclerView = ReflectUtils.reflect(this).field("mRecyclerView").get();
99 | return !(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider) ? null : new LinearSmoothScroller(mRecyclerView.getContext()) {
100 | protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
101 | int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView);
102 | int dx = snapDistances[0];
103 | int dy = snapDistances[1];
104 | int time = this.calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
105 | if (time > 0) {
106 | action.update(dx, dy, time, this.mDecelerateInterpolator);
107 | }
108 |
109 | }
110 |
111 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
112 | return 100.0F / (float) displayMetrics.densityDpi;
113 | }
114 |
115 | protected int calculateTimeForScrolling(int dx) {
116 | return Math.min(MAX_SCROLL_ON_FLING_DURATION, super.calculateTimeForScrolling(dx));
117 | }
118 | };
119 | }
120 |
121 | private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
122 | int childCenter = helper.getDecoratedStart(targetView) + helper.getDecoratedMeasurement(targetView) / 2;
123 | int containerCenter;
124 | if (layoutManager.getClipToPadding()) {
125 | containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
126 | } else {
127 | containerCenter = helper.getEnd() / 2;
128 | }
129 |
130 | return childCenter - containerCenter;
131 | }
132 |
133 | @Nullable
134 | private View findCenterView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
135 | int childCount = layoutManager.getChildCount();
136 | if (childCount == 0) {
137 | return null;
138 | } else {
139 | View closestChild = null;
140 | int center;
141 | if (layoutManager.getClipToPadding()) {
142 | center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
143 | } else {
144 | center = helper.getEnd() / 2;
145 | }
146 | int absClosest = 2147483647;
147 |
148 | for (int i = 0; i < childCount; ++i) {
149 | View child = layoutManager.getChildAt(i);
150 | int childCenter = helper.getDecoratedStart(child) + helper.getDecoratedMeasurement(child) / 2;
151 | int absDistance = Math.abs(childCenter - center);
152 | if (absDistance < absClosest) {
153 | absClosest = absDistance;
154 | closestChild = child;
155 | }
156 | }
157 |
158 | return closestChild;
159 | }
160 | }
161 |
162 | @Nullable
163 | private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
164 | int childCount = layoutManager.getChildCount();
165 | if (childCount == 0) {
166 | return null;
167 | } else {
168 | View closestChild = null;
169 | int startest = 2147483647;
170 |
171 | for (int i = 0; i < childCount; ++i) {
172 | View child = layoutManager.getChildAt(i);
173 | int childStart = helper.getDecoratedStart(child);
174 | if (childStart < startest) {
175 | startest = childStart;
176 | closestChild = child;
177 | }
178 | }
179 |
180 | return closestChild;
181 | }
182 | }
183 |
184 | @NonNull
185 | private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
186 | RecyclerView.LayoutManager mLayoutManager = null;
187 | if (mVerticalHelper != null) {
188 | mLayoutManager = ReflectUtils.reflect(mVerticalHelper).field("mLayoutManager").get();
189 | }
190 | if (this.mVerticalHelper == null || mLayoutManager != layoutManager) {
191 | this.mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
192 | }
193 |
194 | return this.mVerticalHelper;
195 | }
196 |
197 | @NonNull
198 | private OrientationHelper getHorizontalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
199 | RecyclerView.LayoutManager mLayoutManager = null;
200 | if (mHorizontalHelper != null) {
201 | mLayoutManager = ReflectUtils.reflect(mHorizontalHelper).field("mLayoutManager").get();
202 | }
203 | if (this.mHorizontalHelper == null || mLayoutManager != layoutManager) {
204 | this.mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
205 | }
206 |
207 | return this.mHorizontalHelper;
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/utils/layoutmanager/PageLayoutManager.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.utils.layoutmanager;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | import androidx.recyclerview.widget.LinearLayoutManager;
7 | import androidx.recyclerview.widget.RecyclerView;
8 | import androidx.recyclerview.widget.SnapHelper;
9 |
10 | /**
11 | * Date: 2021/1/27
12 | * Author: Yang
13 | * Describe:
14 | */
15 | public class PageLayoutManager extends LinearLayoutManager {
16 |
17 | private final String TAG = this.getClass().getSimpleName();
18 |
19 | private RecyclerView mRecyclerView;
20 | private SnapHelper mPagerSnapHelper;
21 | private PagerChangedListener mOnViewPagerListener;
22 | private int mDrift; // 位移,用来判断移动方向
23 |
24 | public PageLayoutManager(Context context, int orientation) {
25 | super(context, orientation, false);
26 | init();
27 | }
28 |
29 | public PageLayoutManager(Context context, int orientation, boolean reverseLayout) {
30 | super(context, orientation, reverseLayout);
31 | init();
32 | }
33 |
34 | private void init() {
35 | mPagerSnapHelper = new MyPagerSnapHelper();
36 | }
37 |
38 | @Override
39 | public void onAttachedToWindow(RecyclerView view) {
40 | super.onAttachedToWindow(view);
41 | mRecyclerView = view;
42 | mPagerSnapHelper.attachToRecyclerView(view);
43 | mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener);
44 | }
45 |
46 | @Override
47 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
48 | super.onLayoutChildren(recycler, state);
49 | }
50 |
51 | /**
52 | * 滑动状态的改变
53 | * 缓慢拖拽-> SCROLL_STATE_DRAGGING
54 | * 快速滚动-> SCROLL_STATE_SETTLING
55 | * 空闲状态-> SCROLL_STATE_IDLE
56 | */
57 | @Override
58 | public void onScrollStateChanged(int state) {
59 | switch (state) {
60 | case RecyclerView.SCROLL_STATE_IDLE:
61 | View view = mPagerSnapHelper.findSnapView(this);
62 | if (view == null) return;
63 | int position = getPosition(view);
64 | if (mOnViewPagerListener != null && getChildCount() == 1) {
65 | mOnViewPagerListener.onPageSelected(position, position == getItemCount() - 1);
66 | }
67 | break;
68 | }
69 | }
70 |
71 | /** 监听竖直方向的相对偏移量 */
72 | @Override
73 | public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
74 | this.mDrift = dy;
75 | return super.scrollVerticallyBy(dy, recycler, state);
76 | }
77 |
78 |
79 | /** 监听水平方向的相对偏移量 */
80 | @Override
81 | public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
82 | this.mDrift = dx;
83 | return super.scrollHorizontallyBy(dx, recycler, state);
84 | }
85 |
86 | /** 设置监听 */
87 | public void setOnPagerChangeListener(PagerChangedListener listener) {
88 | this.mOnViewPagerListener = listener;
89 | }
90 |
91 | private RecyclerView.OnChildAttachStateChangeListener mChildAttachStateChangeListener
92 | = new RecyclerView.OnChildAttachStateChangeListener() {
93 |
94 | @Override
95 | public void onChildViewAttachedToWindow(View view) {
96 | if (mOnViewPagerListener != null && getChildCount() == 1) {
97 | mOnViewPagerListener.onInitComplete();
98 | }
99 | }
100 |
101 | @Override
102 | public void onChildViewDetachedFromWindow(View view) {
103 | if (mDrift >= 0) {
104 | if (mOnViewPagerListener != null)
105 | mOnViewPagerListener.onPageRelease(true, getPosition(view));
106 | } else {
107 | if (mOnViewPagerListener != null)
108 | mOnViewPagerListener.onPageRelease(false, getPosition(view));
109 | }
110 | }
111 | };
112 |
113 | /** 获取当前的页面下标 */
114 | public int getCurrentPosition() {
115 | View view = mPagerSnapHelper.findSnapView(this);
116 | return view == null ? -1 : getPosition(view);
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/utils/layoutmanager/PagerChangedListener.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.utils.layoutmanager;
2 |
3 | public interface PagerChangedListener {
4 |
5 | /* 初始化完成 */
6 | void onInitComplete();
7 |
8 | /* 释放的监听 */
9 | void onPageRelease(boolean isNext, int position);
10 |
11 | /* 选中的监听以及判断是否滑动到底部 */
12 | void onPageSelected(int position, boolean isBottom);
13 | }
14 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/AbsControllerBar.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.FrameLayout;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | /**
15 | * Date: 2021/3/29
16 | * Author: Yang
17 | * Describe:
18 | */
19 | public abstract class AbsControllerBar extends FrameLayout implements IPDFController {
20 |
21 |
22 | protected List mListener;
23 |
24 | public AbsControllerBar(@NonNull Context context) {
25 | this(context, null);
26 | }
27 |
28 | public AbsControllerBar(@NonNull Context context, @Nullable AttributeSet attrs) {
29 | this(context, attrs, 0);
30 | }
31 |
32 | public AbsControllerBar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
33 | super(context, attrs, defStyleAttr);
34 | initView(context);
35 | }
36 |
37 | protected abstract View getView();
38 |
39 | public void setPreviousText(String previousText) {
40 |
41 | }
42 |
43 | public void setNextText(String nextText) {
44 |
45 | }
46 |
47 |
48 | private void initView(Context context) {
49 | View view = getView();
50 | if (view == null) {
51 | return;
52 | }
53 | addView(view);
54 | mListener = new ArrayList<>();
55 | }
56 |
57 | protected void clickPrevious() {
58 | for (OperateListener listener : mListener) {
59 | if (listener != null) {
60 | listener.clickPrevious();
61 | }
62 | }
63 | }
64 |
65 | protected void clickNext() {
66 | for (OperateListener listener : mListener) {
67 | if (listener != null) {
68 | listener.clickNext();
69 | }
70 | }
71 | }
72 |
73 | @Override
74 | public void addOperateListener(OperateListener listener) {
75 | if (mListener != null && listener != null) {
76 | mListener.add(listener);
77 | }
78 | }
79 |
80 | @Override
81 | public void setPageIndexText(String text) {
82 |
83 | }
84 |
85 | @Override
86 | protected void onDetachedFromWindow() {
87 | super.onDetachedFromWindow();
88 | if (mListener != null) {
89 | mListener.clear();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/IPDFController.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | /**
4 | * Date: 2021/3/19
5 | * Author: Yang
6 | * Describe: PDF控制栏接口
7 | */
8 | public interface IPDFController {
9 |
10 | void addOperateListener(OperateListener listener);
11 |
12 | void setPageIndexText(String text);
13 |
14 | interface OperateListener {
15 |
16 | void clickPrevious();
17 |
18 | void clickNext();
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/LoadingView.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.SweepGradient;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 | import android.view.animation.LinearInterpolator;
11 | import android.view.animation.RotateAnimation;
12 |
13 | public class LoadingView extends View {
14 |
15 | private int strokeWidth;
16 | private int startColor;
17 | private int endColor;
18 | private int duration;
19 | private Paint paint;
20 | private float cx;
21 | private float cy;
22 | private float radius;
23 | private SweepGradient sweepGradient;
24 |
25 | public LoadingView(Context context) {
26 | super(context);
27 | init();
28 | }
29 |
30 | public LoadingView(Context context, AttributeSet attrs) {
31 | super(context, attrs);
32 | init();
33 | }
34 |
35 | public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
36 | super(context, attrs, defStyleAttr);
37 | init();
38 | }
39 |
40 | private int dp(int dp) {
41 | return (int) ((float) dp * this.getResources().getDisplayMetrics().density + 0.5F);
42 | }
43 |
44 | private void init() {
45 | strokeWidth = dp(2);
46 | startColor = Color.TRANSPARENT;
47 | endColor = Color.parseColor("#d8d5d8");
48 | duration = 1200;
49 |
50 | paint = new Paint(Paint.ANTI_ALIAS_FLAG);
51 | paint.setStrokeWidth(strokeWidth);
52 | paint.setStyle(Paint.Style.STROKE);
53 | paint.setStrokeCap(Paint.Cap.ROUND);
54 | paint.setStrokeJoin(Paint.Join.ROUND);
55 | }
56 |
57 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
58 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
59 | cx = getMeasuredWidth() / 2f;
60 | cy = getMeasuredHeight() / 2f;
61 | radius = this.getMeasuredWidth() / 2f - this.strokeWidth / 2f;
62 | sweepGradient = new SweepGradient(cx, cy, new int[]{startColor, endColor}, null);
63 | }
64 |
65 | protected void onDraw(Canvas canvas) {
66 | super.onDraw(canvas);
67 | paint.setShader(sweepGradient);
68 | canvas.drawCircle(cx, cy, radius, paint);
69 | }
70 |
71 | @Override
72 | protected void onAttachedToWindow() {
73 | super.onAttachedToWindow();
74 | RotateAnimation animation = new RotateAnimation(0.0F, 359.0F, 1, 0.5F, 1, 0.5F);
75 | animation.setDuration(duration);
76 | animation.setRepeatCount(-1);
77 | animation.setInterpolator(new LinearInterpolator());
78 | startAnimation(animation);
79 | }
80 |
81 | @Override
82 | protected void onDetachedFromWindow() {
83 | clearAnimation();
84 | super.onDetachedFromWindow();
85 | }
86 | }
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/PDFControllerBar.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.graphics.Typeface;
6 | import android.os.Build;
7 | import android.util.AttributeSet;
8 | import android.util.TypedValue;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.Button;
12 | import android.widget.LinearLayout;
13 | import android.widget.TextView;
14 |
15 | import androidx.annotation.Nullable;
16 |
17 | import com.zjy.pdfview.R;
18 |
19 | import static android.view.Gravity.CENTER;
20 | import static android.widget.LinearLayout.HORIZONTAL;
21 |
22 | /**
23 | * Date: 2021/3/19
24 | * Author: Yang
25 | * Describe: PDF控制栏视图
26 | */
27 | public class PDFControllerBar extends AbsControllerBar implements View.OnClickListener {
28 |
29 | private Button previousBtn, nextBtn;
30 | private TextView pageIndexTv;
31 |
32 | public PDFControllerBar(Context context) {
33 | this(context, null);
34 | }
35 |
36 | public PDFControllerBar(Context context, @Nullable AttributeSet attrs) {
37 | this(context, attrs, 0);
38 | }
39 |
40 | public PDFControllerBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
41 | super(context, attrs, defStyleAttr);
42 | }
43 |
44 | @Override
45 | public View getView() {
46 | LinearLayout rootView= new LinearLayout(getContext());
47 | rootView.setOrientation(HORIZONTAL);
48 | rootView.setGravity(CENTER);
49 | setBackgroundColor(Color.WHITE);
50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
51 | setElevation(dip2px(getContext(), 8));
52 | }
53 |
54 | previousBtn = new Button(getContext());
55 | previousBtn.setBackgroundResource(R.drawable.bg_operate_btn);
56 | previousBtn.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
57 | previousBtn.setText("上一页");
58 | rootView.addView(previousBtn, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dip2px(getContext(), 36)));
59 |
60 | pageIndexTv = new TextView(getContext());
61 | pageIndexTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
62 | pageIndexTv.setPadding(dip2px(getContext(), 16), 0, dip2px(getContext(), 16), 0);
63 | rootView.addView(pageIndexTv, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
64 | pageIndexTv.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
65 | pageIndexTv.setText("1/1");
66 |
67 | nextBtn = new Button(getContext());
68 | nextBtn.setBackgroundResource(R.drawable.bg_operate_btn);
69 | nextBtn.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
70 | nextBtn.setText("下一页");
71 | rootView.addView(nextBtn, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dip2px(getContext(), 36)));
72 |
73 | previousBtn.setOnClickListener(this);
74 | nextBtn.setOnClickListener(this);
75 | return rootView;
76 | }
77 |
78 | @Override
79 | public void onClick(View view) {
80 | if (view == previousBtn) {
81 | clickPrevious();
82 | } else if (view == nextBtn) {
83 | clickNext();
84 | }
85 | }
86 |
87 | @Override
88 | public void setPreviousText(String previousText) {
89 | if (previousBtn != null && previousText != null) {
90 | previousBtn.setText(previousText);
91 | }
92 | }
93 |
94 | @Override
95 | public void setNextText(String nextText) {
96 | if (nextBtn != null && nextText != null) {
97 | nextBtn.setText(nextText);
98 | }
99 | }
100 |
101 | private static int dip2px(Context context, float dpValue) {
102 | final float scale = context.getResources().getDisplayMetrics().density;
103 | return (int) (dpValue * scale + 0.5f);
104 | }
105 |
106 | @Override
107 | public void setPageIndexText(String text) {
108 | if (pageIndexTv != null && text != null) {
109 | pageIndexTv.setText(text);
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/PdfLoadingLayout.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.widget.Button;
8 | import android.widget.FrameLayout;
9 | import android.widget.TextView;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 |
14 | import com.zjy.pdfview.R;
15 | import com.zjy.pdfview.utils.PdfLog;
16 |
17 | /**
18 | * Date: 2021/1/27
19 | * Author: Yang
20 | * Describe:
21 | */
22 | public class PdfLoadingLayout extends FrameLayout {
23 |
24 | TextView waitTv;
25 | Button reloadTv;
26 | View waitLayout;
27 | LoadLayoutListener mListener;
28 |
29 | public PdfLoadingLayout(@NonNull Context context) {
30 | this(context, null);
31 | }
32 |
33 | public PdfLoadingLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
34 | this(context, attrs, 0);
35 | }
36 |
37 | public PdfLoadingLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
38 | super(context, attrs, defStyleAttr);
39 | init();
40 | }
41 |
42 | private void init() {
43 | LayoutInflater.from(getContext()).inflate(R.layout.layout_pdf_loading, this);
44 |
45 | waitTv = findViewById(R.id.waiting_tv);
46 | reloadTv = findViewById(R.id.reload_tv);
47 | waitLayout = findViewById(R.id.waiting_layout);
48 |
49 | reloadTv.setOnClickListener(new OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | if (mListener != null) {
53 | mListener.clickRetry();
54 | }
55 | }
56 | });
57 | }
58 |
59 |
60 | public void showLoading() {
61 | PdfLog.logDebug("showLoading");
62 | setVisibility(VISIBLE);
63 | waitTv.setText("加载中");
64 | reloadTv.setVisibility(GONE);
65 | }
66 |
67 | public void showContent() {
68 | PdfLog.logDebug("showContent");
69 | setVisibility(GONE);
70 | }
71 |
72 | public void showFail() {
73 | setVisibility(VISIBLE);
74 | waitTv.setText("加载失败");
75 | waitLayout.setVisibility(GONE);
76 | reloadTv.setVisibility(VISIBLE);
77 | }
78 |
79 | public void setLoadLayoutListener(LoadLayoutListener listener) {
80 | mListener = listener;
81 | }
82 |
83 | public interface LoadLayoutListener {
84 | void clickRetry();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/PdfRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 |
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | /**
13 | * Date: 2021/1/27
14 | * Author: Yang
15 | * Describe:
16 | */
17 | public class PdfRecyclerView extends RecyclerView {
18 | public PdfRecyclerView(@NonNull Context context) {
19 | super(context);
20 | }
21 |
22 | public PdfRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
23 | super(context, attrs);
24 | }
25 |
26 | public PdfRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
27 | super(context, attrs, defStyle);
28 | }
29 |
30 |
31 | @Override
32 | public boolean onInterceptTouchEvent(MotionEvent e) {
33 | return false;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/ScaleImageView.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Color;
6 | import android.graphics.Matrix;
7 | import android.graphics.PointF;
8 | import android.util.AttributeSet;
9 | import android.view.GestureDetector;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 |
13 | import androidx.annotation.Nullable;
14 | import androidx.appcompat.widget.AppCompatImageView;
15 |
16 | /**
17 | * Date: 2021/1/27
18 | * Author: Yang
19 | * Describe:
20 | */
21 | public class ScaleImageView extends AppCompatImageView {
22 |
23 | private MatrixTouchListener mListener;
24 |
25 | public ScaleImageView(Context context) {
26 | this(context, null);
27 | }
28 |
29 | public ScaleImageView(Context context, @Nullable AttributeSet attrs) {
30 | this(context, attrs, 0);
31 | }
32 |
33 | public ScaleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
34 | super(context, attrs, defStyleAttr);
35 | mListener = new MatrixTouchListener();
36 | setOnTouchListener(mListener);
37 | mGestureDetector = new GestureDetector(getContext(), new GestureListener(mListener));
38 | setBackgroundColor(Color.WHITE);
39 | //将缩放类型设置为FIT_CENTER,表示把图片按比例扩大/缩小到View的宽度,居中显示
40 | setScaleType(ScaleType.FIT_CENTER);
41 | }
42 |
43 | private GestureDetector mGestureDetector;
44 | /**
45 | * 模板Matrix,用以初始化
46 | */
47 | private Matrix mMatrix = new Matrix();
48 | /**
49 | * 图片长度
50 | */
51 | private float mImageWidth;
52 | /**
53 | * 图片高度
54 | */
55 | private float mImageHeight;
56 |
57 | @Override
58 | public void setImageBitmap(Bitmap bm) {
59 | // TODO Auto-generated method stub
60 | super.setImageBitmap(bm);
61 | setScaleType(ScaleType.FIT_CENTER);
62 | mMatrix.reset();
63 | float[] values = new float[9];
64 | mMatrix.getValues(values);
65 |
66 | //setImageMatrix(mMatrix);
67 | mListener.resetListener();
68 | //图片宽度为屏幕宽度除缩放倍数
69 | mImageWidth = bm.getWidth() / values[Matrix.MSCALE_X];
70 | mImageHeight = (bm.getHeight() - values[Matrix.MTRANS_Y] * 2) / values[Matrix.MSCALE_Y];
71 | }
72 |
73 | public void resetScale(int scale) {
74 | //mMatrix.reset();
75 | //mListener.resetListener(scale);
76 | }
77 |
78 | public class MatrixTouchListener implements OnTouchListener {
79 | /**
80 | * 拖拉照片模式
81 | */
82 | private static final int MODE_DRAG = 1;
83 | /**
84 | * 放大缩小照片模式
85 | */
86 | private static final int MODE_ZOOM = 2;
87 | /**
88 | * 不支持Matrix
89 | */
90 | private static final int MODE_UNABLE = 3;
91 | /**
92 | * 最大缩放级别
93 | */
94 | float mMaxScale = 6;
95 | /**
96 | * 双击时的缩放级别
97 | */
98 | float mDoubleClickScale = 2;
99 | private int mMode = 0;//
100 | /**
101 | * 缩放开始时的手指间距
102 | */
103 | private float mStartDis;
104 | /**
105 | * 当前Matrix
106 | */
107 | private Matrix mCurrentMatrix = new Matrix();
108 |
109 | /**
110 | * 用于记录开始时候的坐标位置
111 | */
112 | private PointF startPoint = new PointF();
113 |
114 | public void resetListener() {
115 | mStartDis = 0;
116 | mCurrentMatrix.reset();
117 | startPoint.set(0, 0);
118 | mCurrentMatrix.setScale(1, 1);
119 | setImageMatrix(mCurrentMatrix);
120 | }
121 |
122 | @Override
123 | public boolean onTouch(View v, MotionEvent event) {
124 | // TODO Auto-generated method stub
125 | switch (event.getActionMasked()) {
126 | case MotionEvent.ACTION_DOWN:
127 | //设置拖动模式
128 | mMode = MODE_DRAG;
129 | startPoint.set(event.getX(), event.getY());
130 | isMatrixEnable();
131 | break;
132 | case MotionEvent.ACTION_UP:
133 | case MotionEvent.ACTION_CANCEL:
134 | reSetMatrix();
135 | break;
136 | case MotionEvent.ACTION_MOVE:
137 | if (mMode == MODE_ZOOM) {
138 | setZoomMatrix(event);
139 | } else if (mMode == MODE_DRAG) {
140 | setDragMatrix(event);
141 | }
142 | break;
143 | case MotionEvent.ACTION_POINTER_DOWN:
144 | if (mMode == MODE_UNABLE) return true;
145 | mMode = MODE_ZOOM;
146 | mStartDis = distance(event);
147 | break;
148 | default:
149 | break;
150 | }
151 |
152 | return mGestureDetector.onTouchEvent(event);
153 | }
154 |
155 | public void setDragMatrix(MotionEvent event) {
156 | if (isZoomChanged()) {
157 | float dx = event.getX() - startPoint.x; // 得到x轴的移动距离
158 | float dy = event.getY() - startPoint.y; // 得到x轴的移动距离
159 | //避免和双击冲突,大于10f才算是拖动
160 | if (Math.sqrt(dx * dx + dy * dy) > 10f) {
161 | startPoint.set(event.getX(), event.getY());
162 | //在当前基础上移动
163 | mCurrentMatrix.set(getImageMatrix());
164 | float[] values = new float[9];
165 | mCurrentMatrix.getValues(values);
166 | dx = checkDxBound(values, dx);
167 | dy = checkDyBound(values, dy);
168 | mCurrentMatrix.postTranslate(dx, dy);
169 | setImageMatrix(mCurrentMatrix);
170 | }
171 | }
172 | }
173 |
174 | /**
175 | * 判断缩放级别是否是改变过
176 | *
177 | * @return true表示非初始值, false表示初始值
178 | */
179 | private boolean isZoomChanged() {
180 | float[] values = new float[9];
181 | getImageMatrix().getValues(values);
182 | //获取当前X轴缩放级别
183 | float scale = values[Matrix.MSCALE_X];
184 | //获取模板的X轴缩放级别,两者做比较
185 | mMatrix.getValues(values);
186 | return scale != values[Matrix.MSCALE_X];
187 | }
188 |
189 | /**
190 | * 和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界
191 | *
192 | * @param values
193 | * @param dy
194 | * @return
195 | */
196 | private float checkDyBound(float[] values, float dy) {
197 | float height = getHeight();
198 | if (mImageHeight * values[Matrix.MSCALE_Y] < height)
199 | return 0;
200 | if (values[Matrix.MTRANS_Y] + dy > 0)
201 | dy = -values[Matrix.MTRANS_Y];
202 | else if (values[Matrix.MTRANS_Y] + dy < -(mImageHeight * values[Matrix.MSCALE_Y] - height))
203 | dy = -(mImageHeight * values[Matrix.MSCALE_Y] - height) - values[Matrix.MTRANS_Y];
204 | return dy;
205 | }
206 |
207 | /**
208 | * 和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界
209 | *
210 | * @param values
211 | * @param dx
212 | * @return
213 | */
214 | private float checkDxBound(float[] values, float dx) {
215 | float width = getWidth();
216 | if (mImageWidth * values[Matrix.MSCALE_X] < width)
217 | return 0;
218 | if (values[Matrix.MTRANS_X] + dx > 0)
219 | dx = -values[Matrix.MTRANS_X];
220 | else if (values[Matrix.MTRANS_X] + dx < -(mImageWidth * values[Matrix.MSCALE_X] - width))
221 | dx = -(mImageWidth * values[Matrix.MSCALE_X] - width) - values[Matrix.MTRANS_X];
222 | return dx;
223 | }
224 |
225 | /**
226 | * 设置缩放Matrix
227 | *
228 | * @param event
229 | */
230 | private void setZoomMatrix(MotionEvent event) {
231 | //只有同时触屏两个点的时候才执行
232 | if (event.getPointerCount() < 2) return;
233 | float endDis = distance(event);// 结束距离
234 | if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10
235 | float scale = endDis / mStartDis;// 得到缩放倍数
236 | mStartDis = endDis;//重置距离
237 | mCurrentMatrix.set(getImageMatrix());//初始化Matrix
238 | float[] values = new float[9];
239 | mCurrentMatrix.getValues(values);
240 |
241 | scale = checkMaxScale(scale, values);
242 | setImageMatrix(mCurrentMatrix);
243 | }
244 | }
245 |
246 | /**
247 | * 检验scale,使图像缩放后不会超出最大倍数
248 | *
249 | * @param scale
250 | * @param values
251 | * @return
252 | */
253 | private float checkMaxScale(float scale, float[] values) {
254 | if (scale * values[Matrix.MSCALE_X] > mMaxScale)
255 | scale = mMaxScale / values[Matrix.MSCALE_X];
256 | mCurrentMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);
257 | return scale;
258 | }
259 |
260 | /**
261 | * 重置Matrix
262 | */
263 | private void reSetMatrix() {
264 | if (checkRest()) {
265 | setScaleType(ScaleType.FIT_CENTER);
266 | mCurrentMatrix.set(mMatrix);
267 | setImageMatrix(mCurrentMatrix);
268 | }
269 | }
270 |
271 | /**
272 | * 判断是否需要重置
273 | *
274 | * @return 当前缩放级别小于模板缩放级别时,重置
275 | */
276 | private boolean checkRest() {
277 | // TODO Auto-generated method stub
278 | float[] values = new float[9];
279 | getImageMatrix().getValues(values);
280 | //获取当前X轴缩放级别
281 | float scale = values[Matrix.MSCALE_X];
282 | //获取模板的X轴缩放级别,两者做比较
283 | mMatrix.getValues(values);
284 | return scale < values[Matrix.MSCALE_X];
285 | }
286 |
287 | /**
288 | * 判断是否支持Matrix
289 | */
290 | private void isMatrixEnable() {
291 | //当加载出错时,不可缩放
292 | if (getScaleType() != ScaleType.CENTER) {
293 | setScaleType(ScaleType.MATRIX);
294 | } else {
295 | mMode = MODE_UNABLE;//设置为不支持手势
296 | }
297 | }
298 |
299 | /**
300 | * 计算两个手指间的距离
301 | *
302 | * @param event
303 | * @return
304 | */
305 | private float distance(MotionEvent event) {
306 | float dx = event.getX(1) - event.getX(0);
307 | float dy = event.getY(1) - event.getY(0);
308 | /** 使用勾股定理返回两点之间的距离 */
309 | return (float) Math.sqrt(dx * dx + dy * dy);
310 | }
311 |
312 | /**
313 | * 双击时触发
314 | */
315 | public void onDoubleClick() {
316 | float scale = isZoomChanged() ? 1 : mDoubleClickScale;
317 | mCurrentMatrix.set(mMatrix);//初始化Matrix
318 | mCurrentMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);
319 | setImageMatrix(mCurrentMatrix);
320 | }
321 | }
322 |
323 |
324 | private class GestureListener extends GestureDetector.SimpleOnGestureListener {
325 | private final MatrixTouchListener listener;
326 |
327 | public GestureListener(MatrixTouchListener listener) {
328 | this.listener = listener;
329 | }
330 |
331 | @Override
332 | public boolean onDown(MotionEvent e) {
333 | //捕获Down事件
334 | return true;
335 | }
336 |
337 | @Override
338 | public boolean onDoubleTap(MotionEvent e) {
339 | //触发双击事件
340 | listener.onDoubleClick();
341 | return true;
342 | }
343 |
344 | @Override
345 | public boolean onSingleTapUp(MotionEvent e) {
346 | // TODO Auto-generated method stub
347 | return super.onSingleTapUp(e);
348 | }
349 |
350 | @Override
351 | public void onLongPress(MotionEvent e) {
352 | // TODO Auto-generated method stub
353 | super.onLongPress(e);
354 | }
355 |
356 | @Override
357 | public boolean onScroll(MotionEvent e1, MotionEvent e2,
358 | float distanceX, float distanceY) {
359 | return super.onScroll(e1, e2, distanceX, distanceY);
360 | }
361 |
362 | @Override
363 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
364 | float velocityY) {
365 | // TODO Auto-generated method stub
366 |
367 | return super.onFling(e1, e2, velocityX, velocityY);
368 | }
369 |
370 | @Override
371 | public void onShowPress(MotionEvent e) {
372 | // TODO Auto-generated method stub
373 | super.onShowPress(e);
374 | }
375 |
376 |
377 | @Override
378 | public boolean onDoubleTapEvent(MotionEvent e) {
379 | // TODO Auto-generated method stub
380 | return super.onDoubleTapEvent(e);
381 | }
382 |
383 | @Override
384 | public boolean onSingleTapConfirmed(MotionEvent e) {
385 | // TODO Auto-generated method stub
386 | return super.onSingleTapConfirmed(e);
387 | }
388 |
389 | }
390 | }
391 |
--------------------------------------------------------------------------------
/pdfview/src/main/java/com/zjy/pdfview/widget/ScrollSlider.java:
--------------------------------------------------------------------------------
1 | package com.zjy.pdfview.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.util.AttributeSet;
6 | import android.util.Log;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 | import android.widget.LinearLayout;
11 |
12 | import androidx.annotation.Nullable;
13 |
14 | import com.zjy.pdfview.R;
15 |
16 | import static android.view.Gravity.CENTER;
17 |
18 | public class ScrollSlider extends LinearLayout {
19 |
20 | private float slideDownY;
21 | private ScrollSlideListener listener;
22 |
23 | public ScrollSlider(Context context) {
24 | this(context, null);
25 | }
26 |
27 | public ScrollSlider(Context context, @Nullable AttributeSet attrs) {
28 | this(context, attrs, 0);
29 | }
30 |
31 | public ScrollSlider(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | init();
34 | }
35 |
36 | private void init() {
37 | setOrientation(VERTICAL);
38 | setBackgroundColor(Color.parseColor("#7D000000"));
39 | setGravity(CENTER);
40 | ImageView topArrow = new ImageView(getContext());
41 | topArrow.setImageResource(R.drawable.ic_top_arrow);
42 | addView(topArrow);
43 |
44 | ImageView bottomArrow = new ImageView(getContext());
45 | bottomArrow.setImageResource(R.drawable.ic_top_arrow);
46 | bottomArrow.setRotation(180f);
47 | addView(bottomArrow);
48 |
49 | ((LayoutParams)bottomArrow.getLayoutParams()).topMargin = 20;
50 | }
51 |
52 | @Override
53 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
54 | super.onSizeChanged(w, h, oldw, oldh);
55 | for (int i=0; i
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/layout/activity_pdfrenderer.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
29 |
38 |
39 |
40 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/layout/layout_page_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/layout/layout_pdf_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
14 |
18 |
25 |
26 |
27 |
38 |
39 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/layout/layout_pdf_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
21 |
22 |
23 |
24 |
25 |
32 |
33 |
40 |
41 |
46 |
47 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 下一页
4 | 上一页
5 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | next
4 | previous
5 |
--------------------------------------------------------------------------------
/pdfview/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':pdfview'
2 | include ':app'
3 | rootProject.name = "AndroidPdfHelper"
--------------------------------------------------------------------------------