回答編集履歴
3
修正
test
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
---
|
16
16
|
操作できず表示の確認だけですが、 json を用いるようにしてみました。
|
17
|
-
Span 毎に処理を行う必要があるため、 AbsoluteSizeSpan と ForegroundColorSpan だけに対応です。
|
17
|
+
Span 毎に処理を行う必要があるため、 サンプルとして AbsoluteSizeSpan と ForegroundColorSpan だけに対応です。
|
18
18
|
```java
|
19
19
|
import androidx.appcompat.app.AppCompatActivity;
|
20
20
|
|
2
コード修正
test
CHANGED
@@ -35,7 +35,7 @@
|
|
35
35
|
private static final class SpanObject {
|
36
36
|
private static class What {
|
37
37
|
private static final class Param {
|
38
|
-
String type, value;
|
38
|
+
final String type, value;
|
39
39
|
Param(int value) {
|
40
40
|
type = int.class.getCanonicalName();
|
41
41
|
this.value = "" + value;
|
@@ -43,6 +43,20 @@
|
|
43
43
|
Param(boolean value) {
|
44
44
|
type = boolean.class.getCanonicalName();
|
45
45
|
this.value = "" + value;
|
46
|
+
}
|
47
|
+
Class<?> getType() {
|
48
|
+
switch(type) {
|
49
|
+
case "int": return int.class;
|
50
|
+
case "boolean": return boolean.class;
|
51
|
+
default: return String.class;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
Object getValue() {
|
55
|
+
switch(type) {
|
56
|
+
case "int": return Integer.parseInt(value);
|
57
|
+
case "boolean": return Boolean.parseBoolean(value);
|
58
|
+
default: return value;
|
59
|
+
}
|
46
60
|
}
|
47
61
|
@Override
|
48
62
|
public String toString() { return "[type="+type+",value="+value+"]"; }
|
@@ -64,23 +78,13 @@
|
|
64
78
|
params[0] = new Param(span.getForegroundColor());
|
65
79
|
}
|
66
80
|
Object generate() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
|
67
|
-
Class clazz = Class.forName(className);
|
68
81
|
Class<?>[] paramTypes = new Class[params.length];
|
69
82
|
Object[] initargs = new Object[params.length];
|
70
83
|
for(int i=0; i<params.length; i++) {
|
71
|
-
if(params[i].type.equals("int")) {
|
72
|
-
paramTypes[i] = int.class;
|
73
|
-
initargs[i] = Integer.parseInt(params[i].value);
|
74
|
-
} else if(params[i].type.equals("boolean")) {
|
75
|
-
paramTypes[i] = boolean.class;
|
76
|
-
initargs[i] = Boolean.parseBoolean(params[i].value);
|
77
|
-
} else { //String.class
|
78
|
-
|
84
|
+
paramTypes[i] = params[i].getType();
|
79
|
-
|
85
|
+
initargs[i] = params[i].getValue();
|
80
|
-
|
86
|
+
}
|
81
|
-
}
|
82
|
-
Constructor constructor = clazz.getConstructor(paramTypes);
|
83
|
-
return constructor.newInstance(initargs);
|
87
|
+
return Class.forName(className).getConstructor(paramTypes).newInstance(initargs);
|
84
88
|
}
|
85
89
|
@Override
|
86
90
|
public String toString() {
|
@@ -160,7 +164,7 @@
|
|
160
164
|
editText.setText(ssb);
|
161
165
|
|
162
166
|
EditedText editedText = new EditedText(ssb);
|
163
|
-
|
167
|
+
Log.d("*** toString ***", editedText.toString());
|
164
168
|
|
165
169
|
Gson gson = new Gson();
|
166
170
|
String json = gson.toJson(editedText);
|
1
コード等追加
test
CHANGED
@@ -11,3 +11,224 @@
|
|
11
11
|
と思われます。
|
12
12
|
|
13
13
|
ただ、 realm で保存・再生する為に HTMLを介するのが正しいのかという点は再考する余地はあるように感じます。
|
14
|
+
|
15
|
+
---
|
16
|
+
操作できず表示の確認だけですが、 json を用いるようにしてみました。
|
17
|
+
Span 毎に処理を行う必要があるため、 AbsoluteSizeSpan と ForegroundColorSpan だけに対応です。
|
18
|
+
```java
|
19
|
+
import androidx.appcompat.app.AppCompatActivity;
|
20
|
+
|
21
|
+
import android.graphics.Color;
|
22
|
+
import android.os.*;
|
23
|
+
import android.text.*;
|
24
|
+
import android.text.style.*;
|
25
|
+
import android.util.Log;
|
26
|
+
import android.widget.*;
|
27
|
+
|
28
|
+
import com.google.gson.Gson;
|
29
|
+
import com.google.gson.annotations.SerializedName;
|
30
|
+
|
31
|
+
import java.lang.reflect.*;
|
32
|
+
import java.util.regex.*;
|
33
|
+
|
34
|
+
class EditedText {
|
35
|
+
private static final class SpanObject {
|
36
|
+
private static class What {
|
37
|
+
private static final class Param {
|
38
|
+
String type, value;
|
39
|
+
Param(int value) {
|
40
|
+
type = int.class.getCanonicalName();
|
41
|
+
this.value = "" + value;
|
42
|
+
}
|
43
|
+
Param(boolean value) {
|
44
|
+
type = boolean.class.getCanonicalName();
|
45
|
+
this.value = "" + value;
|
46
|
+
}
|
47
|
+
@Override
|
48
|
+
public String toString() { return "[type="+type+",value="+value+"]"; }
|
49
|
+
}
|
50
|
+
@SerializedName("class")
|
51
|
+
String className;
|
52
|
+
Param[] params;
|
53
|
+
What(Class<?> clazz, int size) {
|
54
|
+
className = clazz.getCanonicalName();
|
55
|
+
params = new Param[size];
|
56
|
+
}
|
57
|
+
What(AbsoluteSizeSpan span) {
|
58
|
+
this(span.getClass(), 2);
|
59
|
+
params[0] = new Param(span.getSize());
|
60
|
+
params[1] = new Param(span.getDip());
|
61
|
+
}
|
62
|
+
What(ForegroundColorSpan span) {
|
63
|
+
this(span.getClass(), 1);
|
64
|
+
params[0] = new Param(span.getForegroundColor());
|
65
|
+
}
|
66
|
+
Object generate() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
|
67
|
+
Class clazz = Class.forName(className);
|
68
|
+
Class<?>[] paramTypes = new Class[params.length];
|
69
|
+
Object[] initargs = new Object[params.length];
|
70
|
+
for(int i=0; i<params.length; i++) {
|
71
|
+
if(params[i].type.equals("int")) {
|
72
|
+
paramTypes[i] = int.class;
|
73
|
+
initargs[i] = Integer.parseInt(params[i].value);
|
74
|
+
} else if(params[i].type.equals("boolean")) {
|
75
|
+
paramTypes[i] = boolean.class;
|
76
|
+
initargs[i] = Boolean.parseBoolean(params[i].value);
|
77
|
+
} else { //String.class
|
78
|
+
paramTypes[i] = Class.forName(params[i].type);
|
79
|
+
initargs[i] = params[i].value;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
Constructor constructor = clazz.getConstructor(paramTypes);
|
83
|
+
return constructor.newInstance(initargs);
|
84
|
+
}
|
85
|
+
@Override
|
86
|
+
public String toString() {
|
87
|
+
StringBuilder sb = new StringBuilder("[");
|
88
|
+
sb.append("class=").append(className);
|
89
|
+
sb.append(",params=[");
|
90
|
+
for(int i=0; i<params.length; i++) sb.append(i > 0 ? "," : "").append(params[i]);
|
91
|
+
sb.append("]");
|
92
|
+
return sb.append("]").toString();
|
93
|
+
}
|
94
|
+
}
|
95
|
+
@SerializedName("object")
|
96
|
+
What what;
|
97
|
+
int start, end, flags;
|
98
|
+
|
99
|
+
@Override
|
100
|
+
public String toString() {
|
101
|
+
StringBuilder sb = new StringBuilder("[");
|
102
|
+
sb.append("what=").append(what);
|
103
|
+
sb.append(",start=").append(start);
|
104
|
+
sb.append(",end=").append(end);
|
105
|
+
sb.append(",flags=").append(flags);
|
106
|
+
return sb.append("]").toString();
|
107
|
+
}
|
108
|
+
}
|
109
|
+
private String text;
|
110
|
+
private SpanObject[] spans;
|
111
|
+
|
112
|
+
EditedText(Spanned spanned) {
|
113
|
+
text = spanned.toString();
|
114
|
+
Object[] spans = spanned.getSpans(0, spanned.length(), Object.class);
|
115
|
+
this.spans = new SpanObject[spans.length];
|
116
|
+
for(int i=0; i<spans.length; i++) {
|
117
|
+
SpanObject span = new SpanObject();
|
118
|
+
if(spans[i] instanceof AbsoluteSizeSpan) {
|
119
|
+
span.what = new SpanObject.What((AbsoluteSizeSpan)spans[i]);
|
120
|
+
} else if(spans[i] instanceof ForegroundColorSpan) {
|
121
|
+
span.what = new SpanObject.What((ForegroundColorSpan)spans[i]);
|
122
|
+
}
|
123
|
+
span.start = spanned.getSpanStart(spans[i]);
|
124
|
+
span.end = spanned.getSpanEnd(spans[i]);
|
125
|
+
span.flags = spanned.getSpanFlags(spans[i]);
|
126
|
+
this.spans[i] = span;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
Spanned toSpanned() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
|
131
|
+
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
|
132
|
+
for(SpanObject span : spans) ssb.setSpan(span.what.generate(), span.start, span.end, span.flags);
|
133
|
+
return ssb;
|
134
|
+
}
|
135
|
+
|
136
|
+
@Override
|
137
|
+
public String toString() {
|
138
|
+
StringBuilder sb = new StringBuilder("[");
|
139
|
+
sb.append("text=").append(text);
|
140
|
+
sb.append(",spans=[");
|
141
|
+
for(int i=0; i<spans.length; i++) sb.append(i > 0 ? "," : "").append(spans[i]);
|
142
|
+
sb.append("]");
|
143
|
+
return sb.append("]").toString();
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
public class MainActivity extends AppCompatActivity {
|
148
|
+
@Override
|
149
|
+
protected void onCreate(Bundle savedInstanceState) {
|
150
|
+
super.onCreate(savedInstanceState);
|
151
|
+
setContentView(R.layout.activity_main);
|
152
|
+
|
153
|
+
EditText editText = findViewById(R.id.editText);
|
154
|
+
TextView textView = findViewById(R.id.textView);
|
155
|
+
|
156
|
+
SpannableStringBuilder ssb = new SpannableStringBuilder("ACDEFG");
|
157
|
+
ssb.setSpan(new AbsoluteSizeSpan(50, true), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
158
|
+
ssb.setSpan(new ForegroundColorSpan(Color.RED), 3, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
159
|
+
//editText.setText("1\n2\n\n3\n\n\n4\n\n\n\n5\n\n\n\n\n6");
|
160
|
+
editText.setText(ssb);
|
161
|
+
|
162
|
+
EditedText editedText = new EditedText(ssb);
|
163
|
+
//Log.d("*** toString ***", editedText.toString());
|
164
|
+
|
165
|
+
Gson gson = new Gson();
|
166
|
+
String json = gson.toJson(editedText);
|
167
|
+
Log.d("*** toJson ***", json);
|
168
|
+
|
169
|
+
EditedText newEdtedText = gson.fromJson(json, EditedText.class);
|
170
|
+
try {
|
171
|
+
textView.setText(newEdtedText.toSpanned());
|
172
|
+
} catch(ClassNotFoundException|
|
173
|
+
InvocationTargetException|
|
174
|
+
NoSuchMethodException|
|
175
|
+
IllegalAccessException|
|
176
|
+
InstantiationException e) {
|
177
|
+
e.printStackTrace();
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
//コントロールコードを文字化
|
182
|
+
private String toText(Spanned htmlSpanned) {
|
183
|
+
StringBuilder sb = new StringBuilder();
|
184
|
+
Pattern p = Pattern.compile("[\u0000-\u001F]");
|
185
|
+
int last = 0;
|
186
|
+
for(Matcher m=p.matcher(htmlSpanned); m.find(last); last=m.end()) {
|
187
|
+
sb.append(htmlSpanned.subSequence(last, m.start()));
|
188
|
+
char c = m.group().charAt(0);
|
189
|
+
sb.append("^").append((char)(c + '@'));
|
190
|
+
}
|
191
|
+
sb.append(htmlSpanned.subSequence(last, htmlSpanned.length()));
|
192
|
+
return sb.toString();
|
193
|
+
}
|
194
|
+
}
|
195
|
+
```
|
196
|
+
res/layout/activity_main.xml
|
197
|
+
```xml
|
198
|
+
<?xml version="1.0" encoding="utf-8"?>
|
199
|
+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
200
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
201
|
+
xmlns:tools="http://schemas.android.com/tools"
|
202
|
+
android:layout_width="match_parent"
|
203
|
+
android:layout_height="match_parent"
|
204
|
+
tools:context=".MainActivity">
|
205
|
+
|
206
|
+
<EditText
|
207
|
+
android:id="@+id/editText"
|
208
|
+
android:layout_width="0dp"
|
209
|
+
android:layout_height="0dp"
|
210
|
+
android:textSize="30dp"
|
211
|
+
app:layout_constraintBottom_toTopOf="@id/textView"
|
212
|
+
app:layout_constraintEnd_toEndOf="parent"
|
213
|
+
app:layout_constraintStart_toStartOf="parent"
|
214
|
+
app:layout_constraintTop_toTopOf="parent" />
|
215
|
+
<TextView
|
216
|
+
android:id="@+id/textView"
|
217
|
+
android:layout_width="0dp"
|
218
|
+
android:layout_height="0dp"
|
219
|
+
android:textSize="30dp"
|
220
|
+
android:background="#e0e0e0"
|
221
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
222
|
+
app:layout_constraintEnd_toEndOf="parent"
|
223
|
+
app:layout_constraintStart_toStartOf="parent"
|
224
|
+
app:layout_constraintTop_toBottomOf="@id/editText" />
|
225
|
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
226
|
+
```
|
227
|
+
エミュレータ実行結果
|
228
|
+

|
229
|
+
実行時ログ
|
230
|
+
```plain
|
231
|
+
D/*** toString ***: [text=ACDEFG,spans=[[what=[class=android.text.style.AbsoluteSizeSpan,params=[[type=int,value=50],[type=boolean,value=true]]],start=2,end=4,flags=33],[what=[class=android.text.style.ForegroundColorSpan,params=[[type=int,value=-65536]]],start=3,end=5,flags=33]]]
|
232
|
+
D/*** toJson ***: {"spans":[{"end":4,"flags":33,"start":2,"object":{"class":"android.text.style.AbsoluteSizeSpan","params":[{"type":"int","value":"50"},{"type":"boolean","value":"true"}]}},{"end":5,"flags":33,"start":3,"object":{"class":"android.text.style.ForegroundColorSpan","params":[{"type":"int","value":"-65536"}]}}],"text":"ACDEFG"}
|
233
|
+
```
|
234
|
+
|