- Span 的分类介绍
- 字符外观,这种类型修改字符的外形但是不影响字符的测量,会触发文本重新绘制但是不触发重新布局。
- ForegroundColorSpan,BackgroundColorSpan,UnderlineSpan,StrikethrougnSpan
- 字符大小布局,这种类型Span会更改文本的大小和布局,会触发文本的重新测量绘制
- StyleSpan,RelativeSizeSpan,AbsoluteSizeSpan
- 影响段落级别,这种类型Span 在段落级别起作用,更改文本块在段落级别的外观,修改对齐方式,边距等。
- AlignmentSpan,BulletSpan,QuoteSpan
- 实现基础样式 粗体、 斜体、 下划线 、中划线 的设置和取消。举个例子,对文本加粗,文字设置span样式注意要点,这里需要区分几种情况
- 当前选中区域不存在 bold 样式 这里我们选中BB。两种情况
- 当前区域紧靠左侧或者右侧不存在粗体样式: AABBCC 这时候直接设置 span即可
- 当前区域紧靠左侧或者右侧存在粗体样式如: AABBCC AABBCC AABBCC。这时候需要合并左右两侧的span,只剩下一个 span
- 当前选中区域存在了Bold 样式 选中 ABBC。四种情况:
- 选中样式两侧不存在连续的bold样式 AABBCC
- 选中内部两端存在连续的bold 样式 AABBCC
- 选中左侧存在连续的bold 样式 AABBCC
- 选中右侧存在连续的bold 样式 AABBCC
- 这时候需要合并左右两侧已经存在的span,只剩下一个 span
- 接下来逐步分解,然后处理span的逻辑顺序如下所示
- 首先对选中文字内容样式情况判断
- 边界判断与设置
- 取消Span(当我们选中的区域在一段连续的 Bold 样式里面的时候,再次选择Bold将会取消样式)
- 什么时候取消span呢,这个逻辑是比较复杂的,具体看看下面的举例。
- 当我们选中的区域在一段连续的 Bold 样式里面的时候,再次选择Bold将会取消样式
- 用户可以随意的删除文本,在删除过程中可能会出现如下的情况:
- 用户输入了 AABBCCDD
- 用户选择了粗体样式 AABBCCDD
- 用户删除了CC然后显示如下 : AABB DD
- 这个时候选中其中的BD 此时,在该区域中 存在两个span ,并且没有一个 span 完全包裹选中的 BD
- 在这种情况下 仍需要进行左右侧边界判断进行删除。这个具体可以看代码逻辑。
08.利用Span对文字属性处理
-
这里仅仅是对字体加粗进行介绍,其实设置span可以找到规律。多个span样式,考虑到后期的拓展性,肯定要进行封装和抽象,具体该如何处理呢?
-
设置文本选中内容加粗模式,代码如下所示,可以看到这里只需要传递一个lastFocusEdit对象即可,这个对象是最近被聚焦的EditText。
/**
-
修改加粗样式
*/
public void bold(EditText lastFocusEdit) {
//获取editable对象
Editable editable = lastFocusEdit.getEditableText();
//获取当前选中的起始位置
int start = lastFocusEdit.getSelectionStart();
//获取当前选中的末尾位置
int end = lastFocusEdit.getSelectionEnd();
HyperLogUtils.i(“bold select Start:” + start + " end: " + end);
if (checkNormalStyle(start, end)) {
return;
}
new BoldStyle().applyStyle(editable, start, end);
} -
然后如何调用这个,在HyperTextEditor类中代码如下所示。为何要这样写,可以把HyperTextEditor富文本类中设置span的逻辑放到SpanTextHelper类中处理,该类专门处理各种span属性,这样代码结构更加清晰,也方便后期增加更多span属性,避免一个类代码太臃肿。
/**
- 修改加粗样式
*/
public void bold() {
SpanTextHelper.getInstance().bold(lastFocusEdit);
}
public void applyStyle(Editable editable, int start, int end) {
//获取 从 start 到 end 位置上所有的指定 class 类型的 Span数组
E[] spans = editable.getSpans(start, end, clazzE);
E existingSpan = null;
if (spans.length > 0) {
existingSpan = spans[0];
}
if (existingSpan == null) {
//当前选中内部无此样式,开始设置span样式
checkAndMergeSpan(editable, start, end, clazzE);
} else {
//获取 一个 span 的起始位置
int existingSpanStart = editable.getSpanStart(existingSpan);
//获取一个span 的结束位置
int existingSpanEnd = editable.getSpanEnd(existingSpan);
if (existingSpanStart <= start && existingSpanEnd >= end) {
//在一个 完整的 span 中
//删除 样式
//
removeStyle(editable, start, end, clazzE, true);
} else {
//当前选中区域存在了某某样式,需要合并样式
checkAndMergeSpan(editable, start, end, clazzE);
}
}
}
09.如何设置插入多张图片
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) {
try{
hte_content.measure(0, 0);
List mSelected = Matisse.obtainResult(data);
// 可以同时插入多张图片
for (Uri imageUri : mSelected) {
String imagePath = HyperLibUtils.getFilePathFromUri(NewActivity.this, imageUri);
Bitmap bitmap = HyperLibUtils.getSmallBitmap(imagePath, scree