先來個(gè)效果圖讓大家看一看,現(xiàn)在好多app都用類似的注冊(cè)頁
實(shí)現(xiàn)思路
- 用一個(gè)透明的EditText與四個(gè)TextView重疊,并給TextView設(shè)置默認(rèn)背景
- 第4個(gè)TextView輸入完成后,要設(shè)置回調(diào),并且要加入增加刪除的回調(diào)
- 還要監(jiān)聽EditText內(nèi)容的變化,獲取內(nèi)容,并且改變EditText下面的TextView的顏色
- 重新發(fā)送的是采用一個(gè)自定義的CountDownTimer類
- 彈出效果自定義的一個(gè)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 ); //將光標(biāo)隱藏 setListener(); } /** * 清空輸入內(nèi)容 */ 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; } |
監(jiān)聽代碼
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) { //重點(diǎn) 如果字符不為""時(shí)才進(jìn)行操作 if (!editable.toString().equals( "" )) { if (stringBuffer.length() > 3 ) { //當(dāng)文本長度大于3位時(shí)edittext置空 editText.setText( "" ); return ; } else { //將文字添加到StringBuffer中 stringBuffer.append(editable); editText.setText( "" ); //添加后將EditText置空 造成沒有文字輸入的錯(cuò)局 // Log.e("TAG", "afterTextChanged: stringBuffer is " + stringBuffer); count = stringBuffer.length(); //記錄stringbuffer的長度 inputContent = stringBuffer.toString(); if (stringBuffer.length() == 4 ) { //文字長度位4 則調(diào)用完成輸入的監(jiān)聽 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 ) { //刪除相應(yīng)位置的字符 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到這了算是結(jié)束了
彈出框的布局
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 = "輸入驗(yàn)證碼表示同意《用戶協(xié)議》" /> < 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 = "重新發(fā)送" android:textColor = "@color/colorPrimary" /> </ LinearLayout > </ LinearLayout > |
[大體的思路,點(diǎn)擊事件之后彈出一個(gè)Dialog,然后再這個(gè)頁面進(jìn)行注冊(cè),有可能這個(gè)Dialog會(huì)復(fù)用,或者改一些樣式(采用Builder設(shè)計(jì)模式)]
接下來自定義Dialog
要實(shí)現(xiàn)EditText的兩個(gè)接口
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 ); //點(diǎn)擊旁白不消失 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( "驗(yàn)證碼輸入錯(cuò)誤" ); text.setTextColor(Color.RED); } } @Override public void deleteContent( boolean isDelete) { if (isDelete) { text.setText( "輸入驗(yàn)證碼表示同意《用戶協(xié)議》" ); text.setTextColor(Color.BLACK); } } } |
至于那個(gè)自定義的CountDownTimer在這里有介紹
Android實(shí)現(xiàn)點(diǎn)擊獲取驗(yàn)證碼60秒后重新獲取功能
源碼地址:Android自定義方框EditText注冊(cè)驗(yàn)證碼
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/macaopark/article/details/69061502