无论什么平台,任何查看器都理应支持多实例模式。不仅仅要支持多实例模式,还要可以切换到单实例模式,而且在多实例下,在外部App重复打开同一文件,可跳转至已有实例,而不会重复打开相同的多实例,这便是设计。
为此,需大量运用 static 全局变量。不必担心内存泄漏,只要不崩溃,就可以在 onDestroy 中释放引用。若是不慎崩溃,整个虚拟进程都被关闭了,又有什么可担心的呢?
从桌面打开主界面有两种选择:
-
打开最近打开的文件。
-
进入历史记录。
主界面UI
底栏:【前进,后退,搜索,书签大纲,宫格更多】
宫格更多 第二底栏(底栏之上)
宫格:【夜间模式,历史记录,书签,设置,缩略图模式,转屏,朗读,页面跳转,进度条,小缩略图,左侧小缩略图,右侧小笔记】
底栏:【退出程序,退离程序,返回】
尼玛这些慢慢做,够我做一年……
先从底栏做起吧,然后定制底栏,然后宫格及其变形动画。
燃鹅时间有限,所以可能取消动画,取消自定义,速战速决……
实现目录。
改进,使之能响应快速的点击事件其实listview也能达到类似的效果(见下方),不过既然有人(似乎是抖音安卓团队)专门抽离出了libarary,就不必再造轮子了,改进就行。寥寥二三文件就不必新建库模块了,源码拉直接拉进去,简单又省事。
之前开发平典查词APP的时候制作的词典管理界面。只有一两层目录结构,仅当有两个及以上词典文件处于相同的目录时,才会显示父文件目录。目录对话框:viewpager,并排【书签,目录,注释列表】
Dialog + viewpager + FragmentPagerAdapter + 以上三个Fragment
需注意 FragmentPagerAdapter 的构造参数。应当传入 getChildFragmentManager() 而不是 getSupportFragmentManager(),否则因为这里是 Dialog 嵌套 Fragment,传全局的FragmentManager会导致APP崩溃(No view found for id … for fragment … 异常)。
既然决定使用 Dialog 了,不妨直接上 DialogFragment。后者的配置更加灵活,既可以当做 Dialog 弹出对话框,又可以选择将之当作普通的 Fragment ,直接加载进入主界面布局。
对话框界面设计分三层:
Toolbar【各种小按钮】
viewpager【书签,目录,注释列表】
TabLayout【书签,目录,注释列表】
拉取PDF目录,需要用到的API有:FPDFBookmark_GetFirstChild、FPDFBookmark_GetNextSibling、FPDFBookmark_GetTitle、FPDFBookmark_GetDest,没有编辑功能。
void recursiveFetchBookMarks(FPDF_DOCUMENT doc, FPDF_BOOKMARK bm, int depth);
// 打印书签标题和页码
void processBookMarks(FPDF_DOCUMENT doc, FPDF_BOOKMARK bm, int depth) {
if(bm) {
long len = FPDFBookmark_GetTitle(bm, 0, 0);
FPDF_WCHAR* buffer = new FPDF_WCHAR[len];
char* bufferStr = new char[2*len];
FPDFBookmark_GetTitle(bm, buffer, len);
WideCharToMultiByte(CP_UTF8, 0, (TCHAR*)buffer, (len+1), bufferStr, 2*len, 0, 0);
std::cout<<"boomark :: ";
for(int i=0;i<depth;i++) {
std::cout<<"-";
}
std::cout<<bufferStr;
FPDF_DEST dest = FPDFBookmark_GetDest(doc, bm);
if (dest != NULL) {
int pageIdx = FPDFDest_GetDestPageIndex(doc, dest);
std::cout<<"……………………"<<pageIdx<<std::endl;
}
}
bm = FPDFBookmark_GetFirstChild(doc, bm);
if(bm) {
recursiveFetchBookMarks(doc, bm, depth+1);
}
}
void recursiveFetchBookMarks(FPDF_DOCUMENT doc, FPDF_BOOKMARK bm, int depth) {
processBookMarks(doc, bm, depth);
if(bm) {
while((bm=FPDFBookmark_GetNextSibling(doc, bm))!=NULL) {
processBookMarks(doc, bm, depth);
}
}
}
...
recursiveFetchBookMarks(doc, 0, 0);
其实 PDF 的书签目录除了页码外,还可以包含一些视图参数,大概是缩放、页面位置这些。既然PDFium不支持编辑书签,那暂时就这样。
先就这样吧,左右两边、工具栏先省省了,逃……记录一下复用这个目录树对话窗口引发的recyclerview不响应notifydatasetchanged调用的bug。(解决fragment嵌套viewpager再嵌套recyclerview导致recyclerview无法正常更新的BUG。)
dismiss并复用后,点击列表中的目录,目录不再展开,recyclerview不更新视图。但是滚动一下recyclerview(即使条目很少无法真正滚动,向上划一下也会有效果。),发现视图更新了,这证明逻辑处理并无问题。那么问题出在哪呢?
答案是 viewpager 的adapter不能被复用。关键在于这个adapter传入了一个getChildFragmentManager()对象。而这玩意儿在对话框dismiss后就会立即失效。所以即使视图是复用的,第二次的onCreateView也需要重新给viewpager设置adapter。
bmView.viewpager.setAdapter(new FragAdapter(getChildFragmentManager(), fragments));
网友评论