分析
初看项目工程目录结构,不是很多,直接看类的字面意思均可以得出一些浅显易懂的知识点
1.看清单文件得出来有4个activity
在ChooseActivity中,添加了多个intent-filter意图过滤器,其作用就是规定一些格式文件,一些支持的类型
2.进入src中
tip :项目代码中大量运用枚举
ChoosePDFActivity是程序的主界面,分类型,是文件夹是就进行打开,pdf就跳转等待结果
ChoosePDFAdapter是加载sd卡文件信息,3中type:上一层,文件夹,文件
MuPDFReflowView继承WebView
MuPDFCore 是声明本地方法并加载so的类:功能用c实现
/* The core rendering instance */
enum TopBarMode {Main, Search, Annot, Delete, More, Accept};
enum AcceptMode {Highlight, Underline, StrikeOut, Ink, CopyText};
3.再看xml
布局文件在 buttons.xml下,采用的是ViewAnimator(视图切换)
draw的逻辑分析
draw相关的类MuPDFActivity MuPDFReaderView ReaderView PageView MuPDFPageView
充分利用 ctrl+shift +F 查找你想要的信息
//墨迹Ink 绘制按钮
public void OnInkButtonClick(View v) {
mTopBarMode = TopBarMode.Accept;
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
mAcceptMode = AcceptMode.Ink;
mDocView.setMode(MuPDFReaderView.Mode.Drawing);
mAnnotTypeText.setText(R.string.ink);
showInfo(getString(R.string.draw_annotation));
}
在源PDF文件上绘制图层,找到触发绘制的事件,追踪绘制的逻辑
MuPDFActivity MuPDFReaderView ReaderView PageView MuPDFPageView
Point类: Point holds two integer coordinates
MuPDFPageView继承PageView
在MuPDFReaderView中
touch事件
touch_start touch_move
在方法中都使用MuPDFView,实现MuPDFView接口,中startDraw continueDraw方法
有个问题:当状态为 Drawing时,双手可以进行缩放
Annot 是Annotation的缩写:代表注释状态
总结如下:
1.mupdfdemo他核心代码是用本地C写的,java调用在MuPDFCore类中
2.几个重要的类分别是
MuPDFActivity控制相关按钮事件
PageView中绘制相关
MuPDFView 继承PageView
reflow 跟重排版文档相关
print 跟打印相关
ordinary 回到TopBarMode.main类型
重点分析MuPDFActivity.java
//注释 点击已绘制区域,可删除//注释 点击已绘制区域,可删除
public void OnDeleteButtonClick(View v) {
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
if (pageView != null)
pageView.deleteSelectedAnnotation();
LogUtils.d(TAG, "OnDeleteButtonClick: ");
mTopBarMode = TopBarMode.Annot;
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
}
//注释 点击已绘制区域,可返回
public void OnCancelDeleteButtonClick(View v) {
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
if (pageView != null)
pageView.deselectAnnotation();
LogUtils.d(TAG, "OnCancelDeleteButtonClick: ");
mTopBarMode = TopBarMode.Annot;
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
}
思路
触摸PDF view 执行的一些事件
ReaderView.java
1。点击屏幕中央:
2.点击屏幕左边或者右边:
2016年2月29日16:05:53
先实现 绘制页面,添加几个按钮:前进,撤销,颜色选择;
实现结果就是在相应模式下面点击新增按钮实现不同的效果
一、实现绘制回退功能
需求:点击画笔之后绘制一笔后,点击此按钮,能够撤销操作
1.
二、实现绘制前进功能(待议)
需求:在撤销操作后,点击此按钮,能够前进操作
三、实现画笔颜色选择功能
需求:选择你想要的画笔颜色,能够绘制不同颜色的笔迹
1.popuwindow
难点:目前mupdf的 绘制功能在pageview中
代码:
//注释 绘制墨迹
if (mDrawing != null) {
LogUtils.d(TAG,"paint的绘制");
Path path = new Path();
PointF p;
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(INK_THICKNESS * scale);
paint.setColor(INK_COLOR);
Iterator<ArrayList<PointF>> it = mDrawing.iterator();
while (it.hasNext()) {
ArrayList<PointF> arc = it.next();
if (arc.size() >= 2) {
Iterator<PointF> iit = arc.iterator();
p = iit.next();
float mX = p.x * scale;
float mY = p.y * scale;
path.moveTo(mX, mY);
while (iit.hasNext()) {
p = iit.next();
float x = p.x * scale;
float y = p.y * scale;
path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
path.lineTo(mX, mY);
} else {
p = arc.get(0);
canvas.drawCircle(p.x * scale, p.y * scale, INK_THICKNESS * scale / 2, paint);
}
}
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, paint);
}
分析
想拿到当前绘制的paint对象,以及绘制的路径path,存入集合中,
问:对paint熟悉吗,撤销和恢复怎么实现
如何保证在绘制过程中不丢帧,即在绘制过程中控制笔迹很流畅
源码分析 找不到 接收保存绘制后的红色笔迹,再议 2016年3月1日17:58:50
头好晕….
2016年3月2日09:28:37 星期三
再次使用AS进行debug调试,定位在接受按钮点击事件方法中 头 尾 2个断点
当进行到最后一句代码时
mDocView.setMode(MuPDFReaderView.Mode.Viewing);
force step into 强制进入内部 观察代码执行过程
最后跟踪到View类中的几个方法
setForegroundTintMode 、getForegroundTintMode、applyForegroundTint
/**
* Applies a tint to the foreground drawable. Does not modify the current tint
* mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
* <p>
* Subsequent calls to {@link #setForeground(Drawable)} will automatically
* mutate the drawable and apply the specified tint and tint mode using
* {@link Drawable#setTintList(ColorStateList)}.
*
* @param tint the tint to apply, may be {@code null} to clear tint
*
* @attr ref android.R.styleable#View_foregroundTint
* @see #getForegroundTintList()
* @see Drawable#setTintList(ColorStateList)
*/
public void setForegroundTintList(@Nullable ColorStateList tint) {
if (mForegroundInfo == null) {
mForegroundInfo = new ForegroundInfo();
}
if (mForegroundInfo.mTintInfo == null) {
mForegroundInfo.mTintInfo = new TintInfo();
}
mForegroundInfo.mTintInfo.mTintList = tint;
mForegroundInfo.mTintInfo.mHasTintList = true;
applyForegroundTint();
}
/**
* Return the tint applied to the foreground drawable, if specified.
*
* @return the tint applied to the foreground drawable
* @attr ref android.R.styleable#View_foregroundTint
* @see #setForegroundTintList(ColorStateList)
*/
@Nullable
public ColorStateList getForegroundTintList() {
return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
? mForegroundInfo.mTintInfo.mTintList : null;
}
/**
* Specifies the blending mode used to apply the tint specified by
* {@link #setForegroundTintList(ColorStateList)}} to the background
* drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
*
* @param tintMode the blending mode used to apply the tint, may be
* {@code null} to clear tint
* @attr ref android.R.styleable#View_foregroundTintMode
* @see #getForegroundTintMode()
* @see Drawable#setTintMode(PorterDuff.Mode)
*/
public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
if (mForegroundInfo == null) {
mForegroundInfo = new ForegroundInfo();
}
if (mForegroundInfo.mTintInfo == null) {
mForegroundInfo.mTintInfo = new TintInfo();
}
mForegroundInfo.mTintInfo.mTintMode = tintMode;
mForegroundInfo.mTintInfo.mHasTintMode = true;
applyForegroundTint();
}
/**
* Return the blending mode used to apply the tint to the foreground
* drawable, if specified.
*
* @return the blending mode used to apply the tint to the foreground
* drawable
* @attr ref android.R.styleable#View_foregroundTintMode
* @see #setForegroundTintMode(PorterDuff.Mode)
*/
@Nullable
public PorterDuff.Mode getForegroundTintMode() {
return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
? mForegroundInfo.mTintInfo.mTintMode : null;
}
private void applyForegroundTint() {
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null
&& mForegroundInfo.mTintInfo != null) {
final TintInfo tintInfo = mForegroundInfo.mTintInfo;
if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate();
if (tintInfo.mHasTintList) {
mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList);
}
if (tintInfo.mHasTintMode) {
mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode);
}
// The drawable (or one of its children) may not have been
// stateful before applying the tint, so let's try again.
if (mForegroundInfo.mDrawable.isStateful()) {
mForegroundInfo.mDrawable.setState(getDrawableState());
}
}
}
}
发现这几个方法都有传入ColorStateList引用,点进去一看,找到了
原来默认的颜色是红色;
再次回到 OnAcceptButtonClick点击方法中来
/*################### 添加注释 #################*/
//注释 这个方法是当用户完成相应操作后,点击保存时的事件
// Edited by Oayiel on ${DATE}.
public void OnAcceptButtonClick(View v) {
LogUtils.d(TAG, "OnAcceptButtonClick: ");
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
boolean success = false;
switch (mAcceptMode) {
case CopyText: //复制文本
if (pageView != null)
success = pageView.copySelection();
mTopBarMode = TopBarMode.More;
showInfo(success?getString(R.string.copied_to_clipboard):getString(R.string.no_text_selected));
break;
case Highlight: //高亮
if (pageView != null)
success = pageView.markupSelection(Annotation.Type.HIGHLIGHT);
mTopBarMode = TopBarMode.Annot;
if (!success)
showInfo(getString(R.string.no_text_selected));
break;
case Underline: //下划线
if (pageView != null)
success = pageView.markupSelection(Annotation.Type.UNDERLINE);
mTopBarMode = TopBarMode.Annot;
if (!success)
showInfo(getString(R.string.no_text_selected));
break;
case StrikeOut: //删除线
if (pageView != null)
success = pageView.markupSelection(Annotation.Type.STRIKEOUT);
mTopBarMode = TopBarMode.Annot;
if (!success)
showInfo(getString(R.string.no_text_selected));
break;
case Ink: //墨迹
//注释 添加va TODO 动画效果
mViewAnimator.setVisibility(View.INVISIBLE);
if (pageView != null)
LogUtils.d(TAG,"保存已经绘制好的墨迹");
success = pageView.saveDraw();
mTopBarMode = TopBarMode.Annot;
if (!success)
showInfo(getString(R.string.nothing_to_save));
break;
}
mTopBarSwitcher.setDisplayedChild(mTopBarMode.ordinal());
mDocView.setMode(MuPDFReaderView.Mode.Viewing); //绘制 回到观察模式
//注释 绘制后的笔迹是走的View--getForegroundTintList--ColorStateList默认的红色
}
经过测试
发现Underline:是蓝色,StrikeOut和Ink默认走的系统红色
不知道从哪改这种颜色 TODO:
修改后保存的文件也能被打开?
@Override
public void onBackPressed() {
//注释 发生绘制事件时,提示用户是否保存
if (core != null && core.hasChanges()) {
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE)
core.save();
finish();
}
};
AlertDialog alert = mAlertBuilder.create();
alert.setTitle("MuPDF");
alert.setMessage(getString(R.string.document_has_changes_save_them_));
alert.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.yes), listener);
alert.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.no), listener);
alert.show();
} else {
super.onBackPressed();
}
}
绘制的 撤销,恢复,画笔颜色,画笔粗细
自定义一个PaintView 实现撤销恢复操作2016年3月2日18:11:22
绘制的功能全是在MuPDFView接口中定义好了
在PageView中与接口中方法同名,如撤销&恢复&保存等,利用子类继承父类并且实现该接口的方式,在activity中click事件中先拿到当前的view对象,强制转换为MuPDFView接口类型
MuPDFView :
public void cancelDraw(int i); //撤销
public class MuPDFPageView extends PageView implements MuPDFView {
MuPDFView pageView = (MuPDFView) mDocView.getDisplayedView();
if (v == mInkBack) {
pageView.cancelDraw(0);
PageView:
MuPDFView:
MuPDFActivity:
Buttons.xml:
txt功能以另一种引擎方式进行打开
之前的想法:方向对了,但是无法与开源项目联系起来
public static ArrayList<View> mViews = new ArrayList<View>();
public static DrawViewListener mDrawViewListener;
public static void setDrawViewListener(DrawViewListener drawViewListener) {
mDrawViewListener = drawViewListener;
}
public interface DrawViewListener {
void onDrawView(View view, ArrayList<ArrayList<PointF>> drawing);
}
//注释 添加事件
/**
* 撤销的核心思想就是将画布清空,
* 将保存下来的Path路径最后一个移除掉,
* 重新将路径画在画布上面。
*/
public void undo() {
LogUtils.d(TAG, "PageView's -- undo");
if (savePath != null && savePath.size() > 0) {
//调用初始化画布函数以清空画布
// initCanvas();
//将路径保存列表中的最后一个元素删除 ,并将其保存在路径删除列表中
DrawPath drawPath = savePath.get(savePath.size() - 1);
deletePath.add(drawPath);
savePath.remove(savePath.size() - 1);
//将路径保存列表中的路径重绘在画布上
Iterator<DrawPath> iter = savePath.iterator(); //重复保存
while (iter.hasNext()) {
DrawPath dp = iter.next();
mCanvas.drawPath(dp.path, dp.paint);
}
invalidate();// 刷新
}
}
/**
* 恢复的核心思想就是将撤销的路径保存到另外一个列表里面(栈),
* 然后从redo的列表里面取出最顶端对象,
* 画在画布上面即可
*/
public void redo() {
LogUtils.d(TAG, "PageView's -- redo");
if (deletePath.size() > 0) {
//将删除的路径列表中的最后一个,也就是最顶端路径取出(栈),并加入路径保存列表中
DrawPath dp = deletePath.get(deletePath.size() - 1);
savePath.add(dp);
//将取出的路径重绘在画布上
mCanvas.drawPath(dp.path, dp.paint);
//将该路径从删除的路径列表中去除
deletePath.remove(deletePath.size() - 1);
invalidate();
}
}
private Canvas mCanvas;
private ArrayList<DrawPath> savePath = new ArrayList<>();
private ArrayList<DrawPath> deletePath = new ArrayList<>();
//路径对象
class DrawPath {
Path path;
Paint paint;
}
试了一下,还是git提交到github保存吧
橡皮擦功能:触摸笔迹消失
选择绘笔粗细 setStrokeWidth
选择绘笔颜色 setColor
复制文本到粘贴板
跳转页面:结合 seekbar(可自定义)
txt文件:给个跳转到另一个解码库
String path = mFiles[position].getAbsolutePath();
if(path.endsWith("txt")){
Toast.makeText(ChoosePDFActivity.this, "PickTXT", Toast.LENGTH_SHORT).show();
//如果点击了txt格式文件,跳转至txt解码器 TODO txt解码
// startActivity(new Intent(this,TXTActivity.class));
}else {
可以新建txt文件,操作
Rss:网络阅读器json
settings:TODO
浏览最近的文件:Vudroid
UI:ChoosePDFItem:Type(PARENT,DIR,DOC),显示对应icon
搜索功能 TODO
TXT文件解码相关
//打开txt文本格式的逻辑
private void open(Bookmark bookmark) {
Intent intent = new Intent(BookmarkListActivity.this, ReadActivity.class);
intent.setData(Uri.parse("file://" + bookmark.getPath()));
startActivity(intent);
}
ReadActivity ReadView BookmarkManager
复制到系统粘贴板
ClipboardManager cbm = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
cbm.setPrimaryClip(ClipData.newPlainText(null, content.toString()));
Typeface typeface = Typeface.createFromAsset(context.getAssets(),"fonts/FZBYSK.TTF");
1
1
https://github.com/lfkdsk/JustWeTools#readview%E5%B0%8F%E8%AF%B4%E9%98%85%E8%AF%BB 不是打广告啊,是这个博主写的真的好
<activity
android:name="com.cinread.ebook.TXTActivity"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="file"/>
<data android:mimeType="*/*"/>
<data android:pathPattern=".*\\.txt"/>
<data android:host="*"/>
</intent-filter>
</activity>
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TXTActivity extends Activity {
private ReadView readView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
File dir = null;
Uri fileUri = getIntent().getData();
if (fileUri != null) {
dir = new File(fileUri.getPath());
}
readView = null;
if (dir != null) {
readView = new ReadView(this,dir.getPath());
}
else
finish();
setContentView(readView);
}
}
String path = mFiles[position].getAbsolutePath();
if(path.endsWith("txt")){
//如果点击了txt格式文件,跳转至txt解码器 TODO txt解码
Intent intent = new Intent(this, TXTActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("file://"+path));
startActivity(intent);
拓展
可以拓展其它功能:笔记/修改,新建笔记;
功能:选择字体大小
选择背景