回答編集履歴

3

TextWatcher の登録時に先のモノを削除するように修正

2022/11/06 12:41

投稿

jimbe
jimbe

スコア12659

test CHANGED
@@ -132,9 +132,13 @@
132
132
  @Override
133
133
  public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
134
134
  Item item = itemList.get(position);
135
- holder.editText.setTag(item);
136
135
  holder.editText.setText(item.text);
136
+
137
+ TextWatcher validator = (TextWatcher)holder.editText.getTag();
138
+ if(validator != null) holder.editText.removeTextChangedListener(validator);
139
+ validator = new EditValidator(holder.editText, item);
140
+ holder.editText.setTag(validator);
137
- holder.editText.addTextChangedListener(new EditValidator(holder.editText, item));
141
+ holder.editText.addTextChangedListener(validator);
138
142
  }
139
143
 
140
144
  @Override

2

残っていた不要コードの削除

2022/11/06 12:30

投稿

jimbe
jimbe

スコア12659

test CHANGED
@@ -65,11 +65,9 @@
65
65
 
66
66
  private static class ViewHolder extends RecyclerView.ViewHolder {
67
67
  final EditText editText;
68
- String text;
69
68
  public ViewHolder(@NonNull View itemView) {
70
69
  super(itemView);
71
70
  editText = itemView.findViewById(R.id.editText);
72
- text = editText.getText().toString();
73
71
  }
74
72
  }
75
73
 

1

コード追加

2022/11/06 09:12

投稿

jimbe
jimbe

スコア12659

test CHANGED
@@ -1,2 +1,204 @@
1
1
  UI そのものの動作の再検討も含めて入力検査・再入力の方法はいろいろで、これしか無いというのは無さそうに思います。
2
2
  フォーカスが移動してしまうのがダメならフォーカスも戻すとか、逆に移動してもどこが問題なのかがはっきり分かるようにどうにかするというのも方法でしょう。
3
+
4
+ ---
5
+ 「TextWatcher 等でバリデートチェックして EditText#setError でエラーを表示するようにしフォーカスは自由に動かせる」というイメージで仕立ててみました。
6
+ DB の更新は考慮していませんが、エラーがあったら SEND ボタンを disable にしています。
7
+
8
+ MainActivity.java
9
+ ```java
10
+ import androidx.annotation.NonNull;
11
+ import androidx.appcompat.app.AppCompatActivity;
12
+ import androidx.recyclerview.widget.RecyclerView;
13
+
14
+ import android.os.*;
15
+ import android.text.*;
16
+ import android.util.Log;
17
+ import android.view.*;
18
+ import android.widget.*;
19
+
20
+ import java.util.*;
21
+
22
+ public class MainActivity extends AppCompatActivity {
23
+ @Override
24
+ protected void onCreate(Bundle savedInstanceState) {
25
+ super.onCreate(savedInstanceState);
26
+ setContentView(R.layout.activity_main);
27
+
28
+ Adapter adapter = new Adapter();
29
+ RecyclerView recyclerView = findViewById(R.id.recyclerView);
30
+ recyclerView.setAdapter(adapter);
31
+
32
+ Button cancelButton = findViewById(R.id.cancelButton);
33
+ cancelButton.setOnClickListener(v -> {
34
+ Log.d("MainActivity **", "cancel.");
35
+ });
36
+
37
+ Button sendButton = findViewById(R.id.sendButton);
38
+ sendButton.setOnClickListener(v -> {
39
+ Log.d("MainActivity **", "send.");
40
+ });
41
+ sendButton.setEnabled(false);
42
+
43
+ adapter.setEventListener(a -> {
44
+ sendButton.setEnabled(a.getErrorCount() == 0);
45
+ });
46
+ }
47
+
48
+ private static class Item {
49
+ final long id;
50
+ final String text;
51
+ Item(long id, String text) {
52
+ this.id = id;
53
+ this.text = text;
54
+ }
55
+ @Override
56
+ public String toString() {
57
+ return super.toString() + "[id=" + id + ", text='" + text + "']";
58
+ }
59
+ }
60
+
61
+ private static class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
62
+ interface AdapterListener extends EventListener {
63
+ void changeState(Adapter adapter);
64
+ }
65
+
66
+ private static class ViewHolder extends RecyclerView.ViewHolder {
67
+ final EditText editText;
68
+ String text;
69
+ public ViewHolder(@NonNull View itemView) {
70
+ super(itemView);
71
+ editText = itemView.findViewById(R.id.editText);
72
+ text = editText.getText().toString();
73
+ }
74
+ }
75
+
76
+ private List<Item> itemList = new ArrayList<>();
77
+ private Set<Long> errorSet = new HashSet<>();
78
+ private AdapterListener listener;
79
+
80
+ Adapter() {
81
+ //テストデータ
82
+ itemList.add(new Item(1, "ABC"));
83
+ itemList.add(new Item(2, "DEF"));
84
+ itemList.add(new Item(3, "GHI"));
85
+ itemList.add(new Item(4, "JKL"));
86
+ }
87
+
88
+ void setEventListener(AdapterListener listener) {
89
+ this.listener = listener;
90
+ if(listener != null) listener.changeState(this); //初期表示用
91
+ }
92
+
93
+ int getErrorCount() {
94
+ return errorSet.size();
95
+ }
96
+
97
+ @NonNull
98
+ @Override
99
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
100
+ return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
101
+ }
102
+
103
+ private class EditValidator implements TextWatcher {
104
+ private EditText editText;
105
+ private Item item;
106
+
107
+ EditValidator(EditText editText, Item item) {
108
+ this.editText = editText;
109
+ this.item = item;
110
+ }
111
+
112
+ private boolean isValid(String text) {
113
+ return text.length() < 5; //テスト用でテキトウ
114
+ }
115
+
116
+ @Override
117
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
118
+ @Override
119
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
120
+ @Override
121
+ public void afterTextChanged(Editable s) {
122
+ boolean changeState;
123
+ if(isValid(s.toString())) {
124
+ editText.setError(null);
125
+ changeState = errorSet.remove(item.id);
126
+ } else {
127
+ editText.setError("length Error");
128
+ changeState = errorSet.add(item.id);
129
+ }
130
+ if(changeState && listener != null) listener.changeState(Adapter.this);
131
+ }
132
+ }
133
+
134
+ @Override
135
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
136
+ Item item = itemList.get(position);
137
+ holder.editText.setTag(item);
138
+ holder.editText.setText(item.text);
139
+ holder.editText.addTextChangedListener(new EditValidator(holder.editText, item));
140
+ }
141
+
142
+ @Override
143
+ public int getItemCount() {
144
+ return itemList.size();
145
+ }
146
+ }
147
+ }
148
+ ```
149
+ res/layout/activity_main.xml
150
+ ```xml
151
+ <?xml version="1.0" encoding="utf-8"?>
152
+ <androidx.constraintlayout.widget.ConstraintLayout
153
+ xmlns:android="http://schemas.android.com/apk/res/android"
154
+ xmlns:tools="http://schemas.android.com/tools"
155
+ xmlns:app="http://schemas.android.com/apk/res-auto"
156
+ android:layout_width="match_parent"
157
+ android:layout_height="match_parent"
158
+ tools:context=".MainActivity">
159
+
160
+ <androidx.recyclerview.widget.RecyclerView
161
+ android:id="@+id/recyclerView"
162
+ android:layout_width="0dp"
163
+ android:layout_height="0dp"
164
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
165
+ app:layout_constraintBottom_toTopOf="@id/topOfButtons"
166
+ app:layout_constraintEnd_toEndOf="parent"
167
+ app:layout_constraintStart_toStartOf="parent"
168
+ app:layout_constraintTop_toTopOf="parent" />
169
+ <androidx.constraintlayout.widget.Barrier
170
+ android:id="@+id/topOfButtons"
171
+ android:layout_width="0dp"
172
+ android:layout_height="0dp"
173
+ app:barrierDirection="top"
174
+ app:constraint_referenced_ids="cancelButton,sendButton" />
175
+ <Button
176
+ android:id="@+id/cancelButton"
177
+ android:layout_width="wrap_content"
178
+ android:layout_height="wrap_content"
179
+ android:text="CANCEL"
180
+ app:layout_constraintBottom_toBottomOf="parent"
181
+ app:layout_constraintEnd_toStartOf="@id/sendButton"
182
+ app:layout_constraintStart_toStartOf="parent" />
183
+ <Button
184
+ android:id="@+id/sendButton"
185
+ android:layout_width="wrap_content"
186
+ android:layout_height="wrap_content"
187
+ android:text="SEND"
188
+ app:layout_constraintBottom_toBottomOf="parent"
189
+ app:layout_constraintEnd_toEndOf="parent"
190
+ app:layout_constraintStart_toEndOf="@id/cancelButton" />
191
+ </androidx.constraintlayout.widget.ConstraintLayout>
192
+ ```
193
+ res/layout/item.xml
194
+ ```xml
195
+ <?xml version="1.0" encoding="utf-8"?>
196
+ <EditText
197
+ xmlns:android="http://schemas.android.com/apk/res/android"
198
+ android:id="@+id/editText"
199
+ android:layout_width="match_parent"
200
+ android:layout_height="wrap_content" />
201
+ ```
202
+
203
+ ![スクリーンショット:エラー無し](https://ddjkaamml8q8x.cloudfront.net/questions/2022-11-06/e3f1aaea-94d4-43d4-b3b4-5e63138dc212.png)
204
+ ![スクリーンショット:エラー有り](https://ddjkaamml8q8x.cloudfront.net/questions/2022-11-06/b85c1c5e-f0a5-4308-bdb1-e2811b64555d.png)