先来个效果图让大家看一看,现在好多app都用类似的注册页
实现思路
- 用一个透明的EditText与四个TextView重叠,并给TextView设置默认背景
- 第4个TextView输入完成后,要设置回调,并且要加入增加删除的回调
- 还要监听EditText内容的变化,获取内容,并且改变EditText下面的TextView的颜色
- 重新发送的是采用一个自定义的CountDownTimer类
- 弹出效果自定义的一个Dialog继承DialogFragment
自定义EditText的布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<? xml version = "1.0" encoding = "utf-8" ?> < RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "match_parent" android:layout_height = "wrap_content" > < LinearLayout android:layout_width = "wrap_content" android:layout_height = "47dp" android:gravity = "center" android:orientation = "horizontal" android:weightSum = "3" > < TextView android:id = "@+id/item_code_iv1" style = "@style/text_editStyle" /> < View android:layout_width = "0dp" android:layout_height = "wrap_content" android:layout_weight = "1" /> < TextView android:id = "@+id/item_code_iv2" style = "@style/text_editStyle" /> < View android:layout_width = "0dp" android:layout_height = "wrap_content" android:layout_weight = "1" /> < TextView android:id = "@+id/item_code_iv3" style = "@style/text_editStyle" /> < View android:layout_width = "0dp" android:layout_height = "wrap_content" android:layout_weight = "1" /> < TextView android:id = "@+id/item_code_iv4" style = "@style/text_editStyle" /> </ LinearLayout > < EditText android:id = "@+id/item_edittext" android:layout_width = "match_parent" android:layout_height = "47dp" android:background = "@android:color/transparent" android:inputType = "number" /> </ RelativeLayout > |
style
1
2
3
4
5
6
7
8
9
|
< style name = "text_editStyle" > < item name = "android:layout_height" >47dp</ item > < item name = "android:layout_width" >47dp</ item > < item name = "android:background" >@mipmap/bg_verify</ item > < item name = "android:gravity" >center</ item > < item name = "android:textColor" >@color/common_blue_0090FF</ item > < item name = "android:textSize" >18sp</ item > </ style > |
View的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
private EditText editText; private TextView[] TextViews; private StringBuffer stringBuffer = new StringBuffer(); private int count = 4 ; private String inputContent; public SecurityCodeView(Context context) { this (context, null ); } public SecurityCodeView(Context context, AttributeSet attrs) { this (context, attrs, 0 ); } public SecurityCodeView(Context context, AttributeSet attrs, int defStyleAttr) { super (context, attrs, defStyleAttr); TextViews = new TextView[ 4 ]; View.inflate(context, R.layout.view_security_code, this ); editText = (EditText) findViewById(R.id.item_edittext); TextViews[ 0 ] = (TextView) findViewById(R.id.item_code_iv1); TextViews[ 1 ] = (TextView) findViewById(R.id.item_code_iv2); TextViews[ 2 ] = (TextView) findViewById(R.id.item_code_iv3); TextViews[ 3 ] = (TextView) findViewById(R.id.item_code_iv4); editText.setCursorVisible( false ); //将光标隐藏 setListener(); } /** * 清空输入内容 */ public void clearEditText() { stringBuffer.delete( 0 , stringBuffer.length()); inputContent = stringBuffer.toString(); for ( int i = 0 ; i < TextViews.length; i++) { TextViews[i].setText( "" ); TextViews[i].setBackgroundResource(R.mipmap.bg_verify); } } private InputCompleteListener inputCompleteListener; public void setInputCompleteListener(InputCompleteListener inputCompleteListener) { this .inputCompleteListener = inputCompleteListener; } public interface InputCompleteListener { void inputComplete(); void deleteContent( boolean isDelete); } /** * 获取输入文本 * * @return */ public String getEditContent() { return inputContent; } |
监听代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
private void setListener() { editText.addTextChangedListener( new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { //重点 如果字符不为""时才进行操作 if (!editable.toString().equals( "" )) { if (stringBuffer.length() > 3 ) { //当文本长度大于3位时edittext置空 editText.setText( "" ); return ; } else { //将文字添加到StringBuffer中 stringBuffer.append(editable); editText.setText( "" ); //添加后将EditText置空 造成没有文字输入的错局 // Log.e("TAG", "afterTextChanged: stringBuffer is " + stringBuffer); count = stringBuffer.length(); //记录stringbuffer的长度 inputContent = stringBuffer.toString(); if (stringBuffer.length() == 4 ) { //文字长度位4 则调用完成输入的监听 if (inputCompleteListener != null ) { inputCompleteListener.inputComplete(); } } } for ( int i = 0 ; i < stringBuffer.length(); i++) { TextViews[i].setText(String.valueOf(inputContent.charAt(i))); TextViews[i].setBackgroundResource(R.mipmap.bg_verify_press); } } } }); editText.setOnKeyListener( new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) { if (onKeyDelete()) return true ; return true ; } return false ; } }); } public boolean onKeyDelete() { if (count == 0 ) { count = 4 ; return true ; } if (stringBuffer.length() > 0 ) { //删除相应位置的字符 stringBuffer.delete((count - 1 ), count); count--; // Log.e(TAG, "afterTextChanged: stringBuffer is " + stringBuffer); inputContent = stringBuffer.toString(); TextViews[stringBuffer.length()].setText( "" ); TextViews[stringBuffer.length()].setBackgroundResource(R.mipmap.bg_verify); if (inputCompleteListener != null ) inputCompleteListener.deleteContent( true ); //有删除就通知manger } return false ; } |
自定义的EditText到这了算是结束了
弹出框的布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:id = "@+id/activity_main" android:layout_width = "283dp" android:layout_height = "273dp" android:layout_gravity = "center" android:layout_marginBottom = "50dp" android:background = "@mipmap/bg_view1" android:orientation = "vertical" > < include layout = "@layout/layout_titile" /> < com.example.admin.myapplication.SecurityCodeView android:id = "@+id/scv_edittext" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_gravity = "center_horizontal" android:layout_marginLeft = "20dp" android:layout_marginRight = "20dp" android:layout_marginTop = "35dp" /> < TextView android:id = "@+id/tv_text" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginLeft = "20dp" android:layout_marginRight = "20dp" android:layout_marginTop = "13dp" android:text = "输入验证码表示同意《用户协议》" /> < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginBottom = "25dp" android:layout_marginTop = "3dp" android:orientation = "horizontal" > < TextView android:id = "@+id/tv_phone" android:layout_width = "0dp" android:layout_height = "wrap_content" android:layout_marginLeft = "20dp" android:layout_marginRight = "20dp" android:layout_marginTop = "13dp" android:layout_weight = "1" android:text = "电话" /> < TextView android:id = "@+id/tv_click" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "20dp" android:layout_marginRight = "20dp" android:layout_marginTop = "13dp" android:text = "重新发送" android:textColor = "@color/colorPrimary" /> </ LinearLayout > </ LinearLayout > |
[大体的思路,点击事件之后弹出一个Dialog,然后再这个页面进行注册,有可能这个Dialog会复用,或者改一些样式(采用Builder设计模式)]
接下来自定义Dialog
要实现EditText的两个接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
|
public class XyAlertDialog extends DialogFragment implements SecurityCodeView.InputCompleteListener { private SecurityCodeView editText; private TextView text; private TextView tv_title; private ImageView img_close; public static final String TAG = XyAlertDialog. class .getSimpleName(); private Builder builder; private static XyAlertDialog instance = new XyAlertDialog(); private TextView tv_phone; private TextView tv_click; public static XyAlertDialog getInstance() { return instance; } @Override public void onCreate( @Nullable Bundle savedInstanceState) { this .setCancelable( true ); setRetainInstance( true ); super .onCreate(savedInstanceState); if (savedInstanceState != null ) { try { if (isAdded() && getActivity() != null ) if (builder != null ) builder = (Builder) savedInstanceState.getSerializable(Builder. class .getSimpleName()); } catch (Exception e) { } } } @Override public void onSaveInstanceState(Bundle outState) { super .onSaveInstanceState(outState); try { if (isAdded() && getActivity() != null ) if (builder != null ) outState.putSerializable(Builder. class .getSimpleName(), builder); } catch (Exception e) { Log.d(TAG, e.toString()); } } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super .onCreateDialog(savedInstanceState); dialog.getWindow().setBackgroundDrawable( new ColorDrawable(android.graphics.Color.TRANSPARENT)); dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); dialog.setCanceledOnTouchOutside( false ); //点击旁白不消失 return dialog; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.activity_xia, container, false ); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super .onViewCreated(view, savedInstanceState); initViews(view); } private Dialog show(Activity activity, Builder builder) { this .builder = builder; if (!isAdded()) show(((AppCompatActivity) activity).getSupportFragmentManager(), TAG); return getDialog(); } private void initViews(View view) { tv_title = (TextView) view.findViewById(R.id.tv_title); img_close = (ImageView) view.findViewById(R.id.img_close); editText = (SecurityCodeView) view.findViewById(R.id.scv_edittext); text = (TextView) view.findViewById(R.id.tv_text); tv_phone = (TextView) view.findViewById(R.id.tv_phone); tv_click = (TextView) view.findViewById(R.id.tv_click); editText.setInputCompleteListener( this ); tv_phone.setText(builder.getTextTitle()); img_close.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { dismiss(); } }); tv_click.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { CountDownTimerUtils mCountDownTimerUtils = new CountDownTimerUtils(tv_click, 60000 , 1000 ); mCountDownTimerUtils.start(); } }); } public static class Builder implements Serializable { private String positiveButtonText; private String negativeButtonText; private String textTitle; private String body; private OnPositiveClicked onPositiveClicked; private OnNegativeClicked onNegativeClicked; private boolean autoHide; private int timeToHide; private int positiveTextColor; private int backgroundColor; private int negativeColor; private int titleColor; private int bodyColor; private Typeface titleFont; private Typeface bodyFont; private Typeface positiveButtonFont; private Typeface negativeButtonFont; private Typeface alertFont; private Context context; private PanelGravity buttonsGravity; public PanelGravity getButtonsGravity() { return buttonsGravity; } public Builder setButtonsGravity(PanelGravity buttonsGravity) { this .buttonsGravity = buttonsGravity; return this ; } public Typeface getAlertFont() { return alertFont; } public Builder setAlertFont(String alertFont) { this .alertFont = Typeface.createFromAsset(context.getAssets(), alertFont); return this ; } public Typeface getPositiveButtonFont() { return positiveButtonFont; } public Builder setPositiveButtonFont(String positiveButtonFont) { this .positiveButtonFont = Typeface.createFromAsset(context.getAssets(), positiveButtonFont); return this ; } public Typeface getNegativeButtonFont() { return negativeButtonFont; } public Builder setNegativeButtonFont(String negativeButtonFont) { this .negativeButtonFont = Typeface.createFromAsset(context.getAssets(), negativeButtonFont); return this ; } public Typeface getTitleFont() { return titleFont; } public Builder setTitleFont(String titleFontPath) { this .titleFont = Typeface.createFromAsset(context.getAssets(), titleFontPath); return this ; } public Typeface getBodyFont() { return bodyFont; } public Builder setBodyFont(String bodyFontPath) { this .bodyFont = Typeface.createFromAsset(context.getAssets(), bodyFontPath); return this ; } public int getTimeToHide() { return timeToHide; } public Builder setTimeToHide( int timeToHide) { this .timeToHide = timeToHide; return this ; } public boolean isAutoHide() { return autoHide; } public Builder setAutoHide( boolean autoHide) { this .autoHide = autoHide; return this ; } public Context getContext() { return context; } public Builder setActivity(Context context) { this .context = context; return this ; } public Builder(Context context) { this .context = context; } public void setCancelable( boolean flag) { throw new RuntimeException( "Stub!" ); } public int getPositiveTextColor() { return positiveTextColor; } public Builder setPositiveColor( int positiveTextColor) { this .positiveTextColor = positiveTextColor; return this ; } public int getBackgroundColor() { return backgroundColor; } public Builder setBackgroundColor( int backgroundColor) { this .backgroundColor = backgroundColor; return this ; } public int getNegativeColor() { return negativeColor; } public Builder setNegativeColor( int negativeColor) { this .negativeColor = negativeColor; return this ; } public int getTitleColor() { return titleColor; } public Builder setTitleColor( int titleColor) { this .titleColor = titleColor; return this ; } public int getBodyColor() { return bodyColor; } public Builder setBodyColor( int bodyColor) { this .bodyColor = bodyColor; return this ; } public String getPositiveButtonText() { return positiveButtonText; } public Builder setPositiveButtonText( int positiveButtonText) { this .positiveButtonText = context.getString(positiveButtonText); return this ; } public Builder setPositiveButtonText(String positiveButtonText) { this .positiveButtonText = positiveButtonText; return this ; } public String getNegativeButtonText() { return negativeButtonText; } public Builder setNegativeButtonText(String negativeButtonText) { this .negativeButtonText = negativeButtonText; return this ; } public Builder setNegativeButtonText( int negativeButtonText) { this .negativeButtonText = context.getString(negativeButtonText); return this ; } public String getTextTitle() { return textTitle; } public Builder setTextTitle(String textTitle) { this .textTitle = textTitle; return this ; } public Builder setTextTitle( int textTitle) { this .textTitle = context.getString(textTitle); return this ; } public String getBody() { return body; } public Builder setBody(String body) { this .body = body; return this ; } public Builder setBody( int body) { this .body = context.getString(body); return this ; } public OnPositiveClicked getOnPositiveClicked() { return onPositiveClicked; } public Builder setOnPositiveClicked(OnPositiveClicked onPositiveClicked) { this .onPositiveClicked = onPositiveClicked; return this ; } public OnNegativeClicked getOnNegativeClicked() { return onNegativeClicked; } public Builder setOnNegativeClicked(OnNegativeClicked onNegativeClicked) { this .onNegativeClicked = onNegativeClicked; return this ; } public Builder build() { return this ; } public Dialog show() { return XyAlertDialog.getInstance().show(((Activity) context), this ); } } @Override public void onPause() { if (isAdded() && getActivity() != null ) { builder = null ; } super .onPause(); } public interface OnPositiveClicked { void OnClick(View view, Dialog dialog); } public interface OnNegativeClicked { void OnClick(View view, Dialog dialog); } public enum PanelGravity { LEFT, RIGHT, CENTER } //EditText的接口 @Override public void inputComplete() { if (!editText.getEditContent().equals( "1234" )) { text.setText( "验证码输入错误" ); text.setTextColor(Color.RED); } } @Override public void deleteContent( boolean isDelete) { if (isDelete) { text.setText( "输入验证码表示同意《用户协议》" ); text.setTextColor(Color.BLACK); } } } |
至于那个自定义的CountDownTimer在这里有介绍
源码地址:Android自定义方框EditText注册验证码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/macaopark/article/details/69061502