Skip to content

Commit b02a399

Browse files
author
ellieshen
committed
设置span字体样式&修复span中间插入字符删除问题
1 parent 6214c32 commit b02a399

File tree

4 files changed

+83
-101
lines changed

4 files changed

+83
-101
lines changed

android/src/main/java/com/variabletextinput/VariableTextInputViewManager.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import androidx.annotation.Nullable;
66
import com.facebook.react.bridge.ReactApplicationContext;
77
import com.facebook.react.bridge.ReadableArray;
8-
import com.facebook.react.bridge.ReadableMap;
98
import com.facebook.react.common.MapBuilder;
109
import com.facebook.react.uimanager.SimpleViewManager;
1110
import com.facebook.react.uimanager.Spacing;
@@ -196,12 +195,7 @@ public void receiveCommand(VariableTextInput root, int commandId, @Nullable Read
196195
break;
197196
}
198197
}
199-
public void insertImage(ReadableArray args) {
200-
ReadableMap mapData = args.getMap(0);
201-
String uri = mapData.getMap("img").getString("uri");
202-
String tag = mapData.getString("tag");
203-
editText.insertImage(uri);
204-
}
198+
205199
@Override
206200
public Map<String, Object> getConstants() {
207201
final Map<String, Object> constants = new HashMap<>();
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.variabletextinput.util;
2+
3+
import android.graphics.Bitmap;
4+
import android.graphics.Canvas;
5+
import android.graphics.Paint;
6+
import android.graphics.Rect;
7+
import android.graphics.Typeface;
8+
9+
public class BitMapUtil {
10+
11+
public static Bitmap getTextBitmap(String name, Typeface typeface, float fontSize, int color) {
12+
Paint paint = new Paint();
13+
paint.setAntiAlias(true);
14+
//设置字体画笔的颜色
15+
paint.setColor(color);
16+
//设置字体的大小
17+
paint.setTextSize(fontSize);
18+
//设置字体
19+
if (typeface != null) {
20+
paint.setTypeface(typeface);
21+
}
22+
Rect rect = new Rect();
23+
paint.getTextBounds(name, 0, name.length(), rect);
24+
// 获取字符串在屏幕上的长度
25+
int width = (int) (paint.measureText(name));
26+
final Bitmap bmp = Bitmap.createBitmap(width, rect.height(), Bitmap.Config.ARGB_8888);
27+
Canvas canvas = new Canvas(bmp);
28+
canvas.drawText(name, rect.left, rect.height() - rect.bottom, paint);
29+
return bmp;
30+
}
31+
}

android/src/main/java/com/variabletextinput/view/VariableTextInput.java

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@
77
import android.graphics.BitmapFactory;
88
import android.graphics.PorterDuff;
99
import android.graphics.Typeface;
10-
import android.graphics.drawable.BitmapDrawable;
1110
import android.graphics.drawable.Drawable;
1211
import android.text.Editable;
13-
import android.text.Spannable;
1412
import android.text.SpannableString;
15-
import android.text.SpannableStringBuilder;
1613
import android.text.Spanned;
1714
import android.text.TextUtils;
1815
import android.text.TextWatcher;
19-
import android.text.style.ImageSpan;
2016
import android.util.DisplayMetrics;
2117
import android.util.Log;
2218
import android.view.Gravity;
@@ -37,6 +33,7 @@
3733
import com.variabletextinput.R;
3834
import com.variabletextinput.bean.RichTextBean;
3935
import com.variabletextinput.util.ActivityConst;
36+
import com.variabletextinput.util.BitMapUtil;
4037
import com.variabletextinput.widget.TextSpan;
4138

4239
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -52,6 +49,7 @@ public class VariableTextInput extends LinearLayout {
5249
private Boolean ignoreNextLocalTextChange = false;
5350

5451
private Context mContext;
52+
private SpannableString mSpannableString;
5553

5654
public VariableTextInput(Context context) {
5755
super(context);
@@ -64,7 +62,7 @@ public VariableTextInput(Context context) {
6462
editText.setLayoutParams(new ScrollView.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
6563
editText.setGravity(Gravity.TOP);
6664
editText.setInputType(editText.getInputType() | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
67-
editText.setPadding(0,0,0,0);
65+
editText.setPadding(0, 0, 0, 0);
6866
// This was used in conjunction with setting raw input type for selecting lock notes.
6967
// However, it causes the keyboard to not come up for editing existing notes.
7068
// Tested while offline using brand new installation on Android 6 emulator, but a user with Android 7 also reported it.
@@ -76,10 +74,22 @@ public VariableTextInput(Context context) {
7674
private int oldHeight = editText.getHeight(); // 保存旧的高度
7775
private int oldWidth = editText.getWidth(); // 保存旧的宽度
7876
private String mPreviousText;
77+
private int mSpanLength = -1;
7978

8079
@Override
8180
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
8281
mPreviousText = s.toString();
82+
if (start == 0 || editText.getText() == null) return;
83+
if (count > after) {
84+
TextSpan[] spans = editText.getText().getSpans(start + count, start + count, TextSpan.class);
85+
if (spans == null || spans.length == 0) return;
86+
for (TextSpan span : spans) {
87+
int endSpanIndex = editText.getText().getSpanEnd(span);
88+
if (endSpanIndex != start + count) continue;
89+
mSpanLength = span.getRichTextBean().content.length() - 1;
90+
editText.getText().removeSpan(span);
91+
}
92+
}
8393
}
8494

8595
@Override
@@ -89,33 +99,21 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
8999
if (count == 0 && before == 0) {
90100
return;
91101
}
92-
if (editText.getText() != null) {
93-
TextSpan[] spans = editText.getText().getSpans(0, editText.getText().length(), TextSpan.class);
94-
ImageSpan[] spansImg = editText.getText().getSpans(0, editText.getText().length(), ImageSpan.class);
95-
//整体删除span
96-
if (before == 1 && count == 0) {
97-
for (TextSpan textSpan : spans) {
98-
if (editText.getText().getSpanEnd(textSpan) == start && !editText.getText().toString().endsWith(textSpan.getRichTextBean().name)) {
99-
editText.getText().delete(editText.getText().getSpanStart(textSpan), editText.getText().getSpanEnd(textSpan));
100-
}
101-
}
102-
for (ImageSpan textSpan : spansImg) {
103-
if (editText.getText().getSpanEnd(textSpan) == start) {
104-
editText.getText().delete(editText.getText().getSpanStart(textSpan), editText.getText().getSpanEnd(textSpan));
105-
}
106-
}
107-
}
102+
String newText = s.toString().substring(start, start + count);
103+
String oldText = mPreviousText.substring(start, start + before);
104+
// Don't send same text changes
105+
if (count == before && newText.equals(oldText)) {
106+
return;
108107
}
109-
// String newText = s.toString().substring(start, start + count);
110-
// String oldText = mPreviousText.substring(start, start + before);
111-
// // Don't send same text changes
112-
// if (count == before && newText.equals(oldText)) {
113-
// return;
114-
// }
115108
if (ignoreNextLocalTextChange) {
116109
ignoreNextLocalTextChange = false;
117110
return;
118111
}
112+
if (editText.getText() != null && mSpanLength > -1) {
113+
int length = mSpanLength;
114+
mSpanLength = -1;
115+
editText.getText().replace(start - length, start, "");
116+
}
119117
WritableMap event = Arguments.createMap();
120118
event.putString("text", s.toString());
121119
final Context context = getContext();
@@ -141,18 +139,20 @@ public void afterTextChanged(Editable s) {
141139
event.putMap("contentSize", contentSize);
142140
final Context context = getContext();
143141
if (context instanceof ReactContext) {
144-
Log.d("输入框高度", "afterTextChanged: "+event);
142+
Log.d("输入框高度", "afterTextChanged: " + event);
145143
((ReactContext) context).getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "onAndroidContentSizeChange", event);
146144
}
147145
}
148146
}
149147
});
150148
}
149+
151150
public int pxToDp(int px) {
152151
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
153152
int dpi = displayMetrics.densityDpi;
154153
return Math.round(px / (dpi / 160f));
155154
}
155+
156156
@Override
157157
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
158158
super.onLayout(changed, left, top, right, bottom);
@@ -317,26 +317,19 @@ public void setPlaceholder(String placeholder) {
317317
public void setUnderLineColorAndroid(Integer color) {
318318
editText.setBackgroundTintList(ColorStateList.valueOf(color));
319319
}
320-
public void setFontSize(Integer fontSize){
320+
321+
public void setFontSize(Integer fontSize) {
321322
editText.setTextSize(fontSize);
322323
}
323-
public void setFontFamily(String fontFamily){
324+
325+
public void setFontFamily(String fontFamily) {
324326
int style = Typeface.NORMAL;
325-
if (editText.getTypeface() != null){
327+
if (editText.getTypeface() != null) {
326328
style = editText.getTypeface().getStyle();
327329
}
328-
Typeface newTypeFace = ReactFontManager.getInstance().getTypeface(fontFamily,style,editText.getContext().getAssets());
330+
Typeface newTypeFace = ReactFontManager.getInstance().getTypeface(fontFamily, style, editText.getContext().getAssets());
329331
editText.setTypeface(newTypeFace);
330332
}
331-
public void insertImage(String imagePath) {
332-
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
333-
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
334-
drawable.setBounds(0, 0, getWidth(), getHeight());
335-
ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
336-
SpannableString spannableString = new SpannableString("face");
337-
spannableString.setSpan(span, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
338-
editText.append(spannableString);
339-
}
340333

341334
public void handleRichText(ReadableArray args) {
342335
if (args != null && args.size() > 0) {
@@ -406,10 +399,10 @@ public void insertEmoji(RichTextBean richTextBean) {
406399
editText.getText().insert(startIndex, richTextBean.tag);
407400
}
408401
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.kuxiao);
409-
ImageSpan imageSpan = new ImageSpan(mContext, bitmap);
410-
SpannableStringBuilder ss = SpannableStringBuilder.valueOf(editText.getText());
411-
ss.setSpan(imageSpan, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
412-
editText.setText(ss);
402+
TextSpan imageSpan = new TextSpan(mContext, bitmap, richTextBean);
403+
mSpannableString = SpannableString.valueOf(editText.getText());
404+
mSpannableString.setSpan(imageSpan, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
405+
editText.setText(mSpannableString);
413406
editText.setSelection(endIndex);
414407
editText.getText().replace(startIndex, endIndex, richTextBean.content);
415408
}
@@ -422,10 +415,11 @@ private void insertMentions(RichTextBean richTextBean) {
422415
if (editText.getText() != null) {
423416
editText.getText().insert(startIndex, richTextBean.tag + richTextBean.name);
424417
}
425-
SpannableStringBuilder ss = SpannableStringBuilder.valueOf(editText.getText());
426-
TextSpan textSpan = new TextSpan(mContext, richTextBean);
427-
ss.setSpan(textSpan, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
428-
editText.setText(ss);
418+
Bitmap bitmap = BitMapUtil.getTextBitmap(richTextBean.tag + richTextBean.name, editText.getTypeface(), editText.getTextSize(), richTextBean.color);
419+
TextSpan textSpan = new TextSpan(mContext, bitmap, richTextBean);
420+
mSpannableString = SpannableString.valueOf(editText.getText());
421+
mSpannableString.setSpan(textSpan, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
422+
editText.setText(mSpannableString);
429423
editText.setSelection(endIndex);
430424
editText.getText().replace(startIndex, endIndex, richTextBean.content);
431425
}

android/src/main/java/com/variabletextinput/widget/TextSpan.java

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,28 @@
22

33
import android.content.Context;
44
import android.graphics.Bitmap;
5-
import android.graphics.Canvas;
6-
import android.graphics.Paint;
7-
import android.graphics.Rect;
8-
import android.graphics.drawable.BitmapDrawable;
9-
import android.graphics.drawable.Drawable;
10-
import android.text.style.DynamicDrawableSpan;
5+
import android.text.style.ImageSpan;
116

12-
import com.variabletextinput.bean.RichTextBean;
7+
import androidx.annotation.NonNull;
138

14-
public class TextSpan extends DynamicDrawableSpan {
9+
import com.variabletextinput.bean.RichTextBean;
1510

11+
public class TextSpan extends ImageSpan {
1612
private Context mContext;
1713
private RichTextBean mRichTextBean;
1814

19-
private Bitmap bitmap;
20-
21-
public TextSpan(Context context, RichTextBean richTextBean) {
15+
public TextSpan(@NonNull Context context, @NonNull Bitmap bitmap, RichTextBean richTextBean) {
16+
super(context, bitmap);
2217
this.mContext = context;
2318
this.mRichTextBean = richTextBean;
24-
this.bitmap = getNameBitmap(richTextBean.tag + richTextBean.name);
2519
}
2620

27-
@Override
28-
public Drawable getDrawable() {
29-
BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(), bitmap);
30-
drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
31-
return drawable;
21+
public Context getContext() {
22+
return mContext;
3223
}
3324

34-
3525
public RichTextBean getRichTextBean() {
3626
return mRichTextBean;
3727
}
3828

39-
public void setRichTextBean(RichTextBean richTextBean) {
40-
this.mRichTextBean = richTextBean;
41-
}
42-
43-
/**
44-
* @param name
45-
* @return
46-
*/
47-
private Bitmap getNameBitmap(String name) {
48-
/* 把@相关的字符串转换成bitmap 然后使用DynamicDrawableSpan加入输入框中 */
49-
Paint paint = new Paint();
50-
paint.setAntiAlias(true);
51-
//设置字体画笔的颜色
52-
paint.setColor(mRichTextBean.color);
53-
//设置字体的大小
54-
paint.setTextSize(50);
55-
Rect rect = new Rect();
56-
paint.getTextBounds(name, 0, name.length(), rect);
57-
// 获取字符串在屏幕上的长度
58-
int width = (int) (paint.measureText(name));
59-
final Bitmap bmp = Bitmap.createBitmap(width, rect.height(), Bitmap.Config.ARGB_8888);
60-
Canvas canvas = new Canvas(bmp);
61-
canvas.drawText(name, rect.left, rect.height() - rect.bottom, paint);
62-
return bmp;
63-
}
64-
6529
}
66-

0 commit comments

Comments
 (0)