Skip to content

Commit f6a1e31

Browse files
committed
修改成光标可定位到图片前面,并处理输入删除文字相关逻辑
1 parent 2603c65 commit f6a1e31

File tree

7 files changed

+70
-30
lines changed

7 files changed

+70
-30
lines changed

richeditor/src/main/java/com/yuruiyin/richeditor/RichEditText.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public class RichEditText extends LineHeightEditText {
6565

6666
private int imageSpanPaddingTop;
6767
private int imageSpanPaddingBottom;
68+
private int imageSpanPaddingLeft;
6869
private int imageSpanPaddingRight;
6970
// 内部限制的图片最大高度
7071
private int internalImageMaxHeight;
@@ -169,6 +170,7 @@ private void init(Context context, AttributeSet attrs) {
169170
mContext = context;
170171
imageSpanPaddingTop = (int) mContext.getResources().getDimension(R.dimen.rich_editor_image_span_padding_top);
171172
imageSpanPaddingBottom = (int) mContext.getResources().getDimension(R.dimen.rich_editor_image_span_padding_bottom);
173+
imageSpanPaddingLeft = (int) mContext.getResources().getDimension(R.dimen.rich_editor_image_span_padding_left);
172174
imageSpanPaddingRight = (int) mContext.getResources().getDimension(R.dimen.rich_editor_image_span_padding_right);
173175
internalImageMaxHeight = (int) mContext.getResources().getDimension(R.dimen.rich_editor_image_max_height);
174176

@@ -344,7 +346,7 @@ public void insertBlockImage(Drawable drawable, @NonNull BlockImageSpanVm blockI
344346

345347
ViewUtil.layoutView(
346348
imageItemView,
347-
resImageWidth + imageSpanPaddingRight,
349+
resImageWidth + imageSpanPaddingLeft + imageSpanPaddingRight,
348350
resImageHeight + imageSpanPaddingTop + imageSpanPaddingBottom
349351
);
350352

richeditor/src/main/java/com/yuruiyin/richeditor/RichTextWatcher.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ public class RichTextWatcher implements TextWatcher {
2222
private int beforeEditContentLen = 0;
2323

2424
// 需要插入回车符的位置,场景:在imageSpan后面输入文字时候需要换行
25-
private int needInsertBreakLinePos = -1;
25+
private int needInsertBreakLinePosAfterImage = -1;
26+
// 是否需要在ImageSpan之前插入换行,场景:在imageSpan前面输入文字时候需要换行
27+
private boolean isNeedInsertBreakLineBeforeImage;
2628

2729
// 上次的输入框内容
2830
private String lastEditTextContent = "";
@@ -69,18 +71,25 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
6971
beforeEditContentLen = s.length();
7072
Editable editable = mEditText.getText();
7173
int curPos = mEditText.getSelectionStart();
72-
if (curPos == 0) {
73-
needInsertBreakLinePos = -1;
74-
return;
75-
}
7674

77-
BlockImageSpan[] blockImageSpans = editable.getSpans(curPos - 1, curPos, BlockImageSpan.class);
78-
if (blockImageSpans.length > 0) {
79-
//说明当前光标处于imageSpan的后面,如果在当前位置输入文字,需要另起一行
80-
needInsertBreakLinePos = curPos;
75+
// 判断是否在图片后输入
76+
if (curPos == 0) {
77+
needInsertBreakLinePosAfterImage = -1;
8178
} else {
82-
needInsertBreakLinePos = -1;
79+
// 判断是否在图片后面输入
80+
BlockImageSpan[] blockImageSpansAfter = editable.getSpans(curPos - 1, curPos, BlockImageSpan.class);
81+
if (blockImageSpansAfter.length > 0) {
82+
//说明当前光标处于imageSpan的后面,如果在当前位置输入文字,需要另起一行
83+
needInsertBreakLinePosAfterImage = curPos;
84+
} else {
85+
needInsertBreakLinePosAfterImage = -1;
86+
}
8387
}
88+
89+
// 判断是否在图片前面输入
90+
BlockImageSpan[] blockImageSpansBefore = editable.getSpans(curPos, curPos + 1, BlockImageSpan.class);
91+
// 说明当前光标在ImageSpan的前面
92+
isNeedInsertBreakLineBeforeImage = blockImageSpansBefore.length > 0;
8493
}
8594

8695
@Override
@@ -101,10 +110,19 @@ public void afterTextChanged(Editable s) {
101110

102111
int cursorPos = mEditText.getSelectionStart();
103112
String editContent = s.toString();
104-
if (needInsertBreakLinePos != -1 &&
113+
if (needInsertBreakLinePosAfterImage != -1 &&
105114
cursorPos > 0 && editContent.charAt(cursorPos - 1) != '\n') {
106115
//在imageSpan后面输入了文字(除了'\n'),则需要换行
107-
s.insert(needInsertBreakLinePos, "\n");
116+
s.insert(needInsertBreakLinePosAfterImage, "\n");
117+
}
118+
119+
if (isNeedInsertBreakLineBeforeImage && cursorPos >= 0) {
120+
// 在ImageSpan前输入回车, 则需要将光标移动到上一个行
121+
// 在ImageSpan前输入文字(除了'\n'),则需要先换行,在将光标移动到上一行
122+
if (editContent.charAt(cursorPos - 1) != '\n') {
123+
s.insert(cursorPos, "\n");
124+
}
125+
mEditText.setSelection(cursorPos);
108126
}
109127

110128
if (cursorPos > 0 && editContent.charAt(cursorPos - 1) == '\n' && !editContent.equals(lastEditTextContent)) {

richeditor/src/main/java/com/yuruiyin/richeditor/RichUtils.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ void insertNormalTextBlock(SpannableString content, List<RichEditorBlock.InlineS
136136
insertStringIntoEditText(content, cursorPos);
137137
}
138138

139+
/**
140+
* 判断光标是否处于行首
141+
*/
142+
private boolean isCursorInFirstIndexOfLine() {
143+
int cursor = mRichEditText.getSelectionStart();
144+
if (cursor < 0 || mRichEditText.length() <= 0) {
145+
return true;
146+
}
147+
148+
Editable editable = mRichEditText.getEditableText();
149+
return cursor == 0 || editable.charAt(cursor - 1) == '\n';
150+
}
151+
139152
/**
140153
* 在光标位置插入段落ImageSpan(如图片、视频封面、自定义view等)
141154
*
@@ -147,7 +160,7 @@ void insertBlockImageSpan(BlockImageSpan blockImageSpan) {
147160
}
148161

149162
// 只有正常编辑器插入的ImageSpan才在前面都插入一空行,否则从草稿插入的不再另外加一空行
150-
if (!blockImageSpan.getBlockImageSpanVm().isFromDraft()) {
163+
if (!blockImageSpan.getBlockImageSpanVm().isFromDraft() && !isCursorInFirstIndexOfLine()) {
151164
insertStringIntoEditText("\n", mRichEditText.getSelectionStart());
152165
}
153166

@@ -925,18 +938,11 @@ private void changeCursorHeight() {
925938
* @param cursorPos 当前光标位置
926939
*/
927940
private void handleSelectionChanged(int cursorPos) {
928-
//如果光标定位到了imagespan的前面,则将光标移动到imageSpan的后面
929941
Editable editable = mRichEditText.getEditableText();
930942
if (editable.length() <= 0 && cursorPos <= 0) {
931943
mRichEditText.requestFocus();
932944
mRichEditText.setSelection(0);
933945
}
934-
ImageSpan[] imageSpans = editable.getSpans(cursorPos, cursorPos + 1, ImageSpan.class);
935-
if (imageSpans.length > 0) {
936-
//说明光标在ImageSpan的前面
937-
mRichEditText.setSelection(cursorPos + 1);
938-
return;
939-
}
940946

941947
// 先合并指定位置前后连续的行内样式
942948
for (String type : mRichTypeToVmMap.keySet()) {
@@ -959,6 +965,7 @@ private void handleSelectionChanged(int cursorPos) {
959965
* 1、删除BlockImageSpan的时候,直接将光标定位到上一行末尾
960966
* 2、当光标处于BlockImageSpan下一行的第一个位置(不是EditText最后一个字符)上按删除按键时,
961967
* 不删除字符,而是将光标定位到上一行的末尾(即BlockImageSpan的末尾)
968+
* 3、当光标处于BlockImageSpan的行首按删除按键时,如果上一行不是空行,则不删除字符,而是将光标移动到上一行的末尾
962969
*/
963970
private boolean handleDeleteKey() {
964971
Editable editable = mRichEditText.getEditableText();
@@ -988,6 +995,14 @@ private boolean handleDeleteKey() {
988995
return true;
989996
}
990997

998+
// 当光标处于BlockImageSpan的行首按删除按键时,如果上一行不是空行,则不删除字符,而是将光标移动到上一行的末尾
999+
BlockImageSpan[] imageSpans2 = editable.getSpans(cursorPos, cursorPos + 1, BlockImageSpan.class);
1000+
if (imageSpans2.length > 0 && cursorPos >= 2
1001+
&& content.charAt(cursorPos - 1) == '\n' && content.charAt(cursorPos - 2) != '\n') {
1002+
mRichEditText.setSelection(cursorPos - 1);
1003+
return true;
1004+
}
1005+
9911006
return false;
9921007
}
9931008

richeditor/src/main/java/com/yuruiyin/richeditor/ext/LongClickableLinkMovementMethod.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent
3232
switch (action) {
3333
case MotionEvent.ACTION_DOWN:
3434
mPressedSpan = getPressedSpan(textView, spannable, event);
35-
if (mPressedSpan != null) { //点击span区域
36-
Selection.setSelection(spannable, spannable.getSpanStart(mPressedSpan),
37-
spannable.getSpanEnd(mPressedSpan));
38-
}
35+
// if (mPressedSpan != null) { //点击span区域
36+
// Selection.setSelection(spannable, spannable.getSpanStart(mPressedSpan),
37+
// spannable.getSpanEnd(mPressedSpan));
38+
// }
3939
break;
4040
case MotionEvent.ACTION_MOVE:
4141
BlockImageSpan touchedSpan = getPressedSpan(textView, spannable, event);
@@ -49,7 +49,7 @@ public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent
4949
if (MotionEvent.ACTION_UP == action) {
5050
mPressedSpan.onClick(textView);
5151
}
52-
super.onTouchEvent(textView, spannable, event);
52+
// super.onTouchEvent(textView, spannable, event);
5353
}
5454
mPressedSpan = null;
5555
// safeRemoveSpan(spannable);

richeditor/src/main/java/com/yuruiyin/richeditor/span/BlockImageSpan.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
*/
2424
public class BlockImageSpan extends CenterImageSpan implements LongClickableSpan {
2525

26+
// 手指触摸到图片左侧之后,当成光标移动到左侧,不响应图片点击事件
27+
private static final int TOUCH_OFFSET_X = 45;
28+
2629
private float x;
2730
private float y;
2831

@@ -80,7 +83,7 @@ public boolean clicked(int touchX, int touchY) {
8083
Drawable drawable = getDrawable();
8184
if (drawable != null) {
8285
Rect rect = drawable.getBounds();
83-
return touchX <= rect.right + x && touchX >= rect.left + x
86+
return touchX <= rect.right + x && touchX >= rect.left + x + TOUCH_OFFSET_X
8487
&& touchY <= rect.bottom + y && touchY >= rect.top + y;
8588
}
8689
return false;

richeditor/src/main/res/layout/rich_editor_image.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
android:layout_height="wrap_content"
77
android:paddingBottom="@dimen/rich_editor_image_span_padding_bottom"
88
android:paddingRight="@dimen/rich_editor_image_span_padding_right"
9+
android:paddingLeft="@dimen/rich_editor_image_span_padding_left"
910
android:paddingTop="@dimen/rich_editor_image_span_padding_top"
1011
>
1112

richeditor/src/main/res/values/dimens.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
<dimen name="rich_editor_quote_text_size">18dp</dimen>
1818

1919
<!-- 发表长文编辑区中块级图片元素的padding -->
20-
<dimen name="rich_editor_image_span_padding_top">15dp</dimen>
21-
<dimen name="rich_editor_image_span_padding_bottom">15dp</dimen>
22-
<dimen name="rich_editor_image_span_padding_right">2dp</dimen>
20+
<dimen name="rich_editor_image_span_padding_top">10dp</dimen>
21+
<dimen name="rich_editor_image_span_padding_bottom">10dp</dimen>
22+
<dimen name="rich_editor_image_span_padding_right">1dp</dimen>
23+
<dimen name="rich_editor_image_span_padding_left">1dp</dimen>
2324

2425
<!-- 限制图片最大的高度,避免调用方传递超级大的高度而导致长图限制超级长的问题 -->
2526
<dimen name="rich_editor_image_width">120dp</dimen>

0 commit comments

Comments
 (0)