神马笔记 版本1.7.0——辅助编辑·代码篇
一、目标
定义实现辅助编辑的整体代码框架。
二、体验地址
神马笔记最新版本下载:【神马笔记 版本1.7.0——辅助编辑功能.apk】
三、代码结构
与辅助编辑有关的代码均位于app.haiyunshan.whatsnote.outline
包之下。
1. 包结构
app.haiyunshan.whatsnote.outline
OutlineFragment
IndentDialogFragment
IndentFragment
app.haiyunshan.whatsnote.outline.entity
Outline
BaseOutlineEntity
ParagraphOutlineEntity
PictureOutlineEntity
app.haiyunshan.whatsnote.outline.viewholder
BaseOutlineViewHolder
ParagraphOutlineViewHolder
PictureOutlineViewHolder
app.haiyunshan.whatsnote.outline.helper
OutlineHelper
OutlineFactory
Package | Summary |
---|---|
app.haiyunshan.whatsnote.outline | Fragment级别的用户交互类 |
app.haiyunshan.whatsnote.outline.entity | 交互数据类 |
app.haiyunshan.whatsnote.outline.viewholder | RecyclerView的ViewHolder类 |
app.haiyunshan.whatsnote.outline.helper | 助手类 |
2. 界面类
app.haiyunshan.whatsnote.outline | Summary |
---|---|
OutlineFragment | 大纲结构界面 |
IndentDialogFragment | 段落缩进对话框 |
IndentFragment | 段落缩进界面 |
3. 交互数据类
app.haiyunshan.whatsnote.outline.entity | Summary |
---|---|
Outline | 文章大纲数据集合类 |
BaseOutlineEntity | 段落和图片基类 |
ParagraphOutlineEntity | 段落类 |
PictureOutlineEntity | 图片类 |
4. ViewHolder类
app.haiyunshan.whatsnote.outline.viewholder | Summary |
---|---|
BaseOutlineViewHolder | 段落和图片基类,与BaseOutlineEntity 对应。 |
ParagraphOutlineViewHolder | 段落类,与ParagraphOutlineEntity 对应。 |
PictureOutlineViewHolder | 图片类,与PictureOutlineEntity 对应。 |
5. 助手类
app.haiyunshan.whatsnote.outline.helper | Summary |
---|---|
OutlineHelper | 大纲结构管理助手类。 |
OutlineFactory | 大纲结构工厂类,负责Document与Outline的相互转换。 |
四、布局资源
1. 列表项布局
段落和图片的布局唯一的差别只是显示内容控件的不同,前者为TextView,后者为ImageView。其他所有布局都是相同的,因此定义通用的布局资源,预留ViewStub用于段落和图片加载自身的布局资源。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/settingItemHeight"
android:background="@color/colorWindowBackground">
<FrameLayout
android:id="@+id/btn_delete"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_red_light"
android:foreground="?selectableItemBackground">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="left"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:text="删除"
android:textStyle="bold"
android:textColor="@android:color/white"
android:textAppearance="@style/TextAppearance.AppCompat.Button"/>
</FrameLayout>
<LinearLayout
android:id="@+id/swipe_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="@dimen/settingItemHeight"
android:paddingLeft="?listPreferredItemPaddingLeft"
android:paddingRight="?listPreferredItemPaddingRight"
android:background="@color/colorWindowBackground"
android:foreground="?selectableItemBackground"
android:clipToPadding="false"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_gravity="center">
<ImageView
android:id="@+id/iv_checkbox"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@null"
android:background="@drawable/anc_ic_circle_color_stroke"
android:tint="@color/colorPrimary"
android:backgroundTint="@color/colorChevron"
android:scaleType="fitCenter"
android:layout_gravity="left|center_vertical"
android:visibility="visible"
android:duplicateParentState="false"
android:layout_marginRight="?listPreferredItemPaddingRight"/>
<ImageView
android:id="@+id/iv_icon"
android:layout_marginRight="?listPreferredItemPaddingRight"
android:layout_width="24dp"
android:layout_height="24dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_paragraph_outline"
android:tint="@color/colorOutlineIcon"
android:visibility="gone"
/>
<ViewStub
android:id="@+id/stub"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="left|center_vertical"/>
<ImageView
android:id="@+id/btn_drag"
android:layout_width="28dp"
android:layout_height="28dp"
android:src="@drawable/ic_drag_handle_white_24dp"
android:tint="@color/colorDrag"
android:scaleType="centerInside"
android:visibility="visible"
android:layout_gravity="right|center_vertical"
android:layout_marginLeft="?listPreferredItemPaddingLeft"/>
</LinearLayout>
</FrameLayout>
2. 段落布局
替换列表项布局中的ViewStub。
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_name"
android:textAppearance="@style/TextAppearance.AppCompat.Menu"
android:layout_width="0dp"
android:gravity="left|center_vertical"
android:layout_height="match_parent"
android:singleLine="true"
android:lines="1"
android:layout_weight="1"/>
3. 图片布局
替换列表项布局中的ViewStub。
设置scaleType为fitXY,伸缩图片适应控件大小。
设置background为圆角矩形,并配合outlineProvider实现裁剪,实现圆角图片效果。
设置foreground,为控件添加Stroke。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:scaleType="fitXY"
android:background="@drawable/shape_picture_outline_bg"
android:foreground="@drawable/shape_picture_outline_fg"
android:outlineProvider="background"/>
</FrameLayout>
五、实现要点
1. OutlineFactory
OutlineFactory
实现了Document
和Outline
的相互转换。需要注意的是Outline
转换为Document
时。
- 内容不能为空
- 最后一个必须是段落,以保证用户可以继续编辑
- 第一个必须是段落,以保证用户可以编写标题
2. BaseOutlineEntity
public class BaseOutlineEntity<T extends DocumentEntity> {
String id;
T parent;
BaseOutlineEntity(T parent) {
this.parent = parent;
this.id = UUIDUtils.next();
}
public String getId() {
return this.id;
}
public String getParentId() {
return parent.getId();
}
public T getParent() {
return parent;
}
public void indent(CharSequence prefix) {
// 由子类实现缩进
}
public void delete() {
// 由子类实现删除
}
}
3. BaseOutlineViewHolder
由于通过反射方式创建BaseOutlineViewHolder
的子类们,必须保证构造函数不被混淆。因此必须使用@Keep注解标注构造函数。
public class BaseOutlineViewHolder<T extends BaseOutlineEntity> extends SwipeViewHolder<T> {
public static final int LAYOUT_RES_ID = R.layout.layout_outline_list_item;
ImageView checkBox;
ImageView iconView;
ViewStub viewStub;
ImageView dragView;
OutlineHelper helper;
@Keep
public BaseOutlineViewHolder(OutlineHelper helper, View itemView) {
super(itemView);
this.helper = helper;
}
@Override
public int getLayoutResourceId() {
return LAYOUT_RES_ID;
}
// ……
}
六、实现过程
欲知后事如何,且听下回分解。
七、Finally
~还似旧时游上苑~车如流水马如龙~