驗證碼基本上是每個專案都需要用到的功能,這篇文章完成了一個驗證碼的輸入框效果,並且擴充了一個輸入上傳車牌號(包括新能源),自定義鍵盤等功能。作者會根據自己的實現的思路來闡述一下功能的實現
驗證碼輸入的實現
先看一下效果
實現思路是:
首先讓鍵盤彈起來
使用TextField讓鍵盤彈起來,並且通過設定TextField的屬性,讓使用者感覺不到TextField的存在
TextField(
maxLength: 6,
onChanged: (value) {
},
controller: controller,
cursorWidth: 0,
cursorColor: Colors.transparent,
keyboardType: TextInputType.number,
style: TextStyle(color: Colors.transparent),
decoration: InputDecoration(
border: InputBorder.none,
counterText: '',
),
),
複製程式碼
這樣就完全看不到TextField 的存在並且點選可以彈起鍵盤
展示輸入的驗證碼
使用stack佈局,在最低層構建一排container設定邊框,然後將TextField放在其上面,這樣就會可以了,再監聽onChanged方法,進行遍歷TextField的輸入值,顯示在一排排的container上面。
Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: dataList
.map<Widget>((e) => renderContainer(e))
.toList(),
),
TextField(
maxLength: 6,
onChanged: (value) {
List data = [];
for (int i = 0; i < value.length; i++) {
data.add(value.substring(i, i + 1));
}
data = fillData(data);
if (mounted) {
setState(() {
dataList = data;
});
}
},
controller: controller,
cursorWidth: 0,
cursorColor: Colors.transparent,
keyboardType: TextInputType.number,
style: TextStyle(color: Colors.transparent),
decoration: InputDecoration(
border: InputBorder.none,
counterText: '',
),
),
],
)
複製程式碼
基本程式碼完成了,下面是全部程式碼
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
class CarInputPage extends StatefulWidget {
CarInputPage({Key key}) : super(key: key);
@override
_CarInputPageState createState() => _CarInputPageState();
}
class _CarInputPageState extends State<CarInputPage> {
TextEditingController controller = TextEditingController();
List dataList = ['', '', '', '', '', ''];
renderContainer(title) {
return Container(
width: 60,
height: 80,
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border.all(
color: title == '' ? Colors.green : Colors.blue, width: 2)),
child: Text(
title,
style: TextStyle(fontSize: 18, color: Colors.blue),
),
);
}
List fillData(List data) {
if (data.length < 6) {
data.add('');
this.fillData(data);
}
return data;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: customAppbar(title: '繫結車輛'),
body: GestureDetector(
onTap: () {
print('object');
SystemChannels.textInput.invokeMethod('TextInput.hide');
},
child: Container(
width: Get.width,
decoration: BoxDecoration(color: Colors.white),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Column(
children: [
Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: dataList
.map<Widget>((e) => renderContainer(e))
.toList(),
),
TextField(
maxLength: 6,
onChanged: (value) {
List data = [];
for (int i = 0; i < value.length; i++) {
data.add(value.substring(i, i + 1));
}
data = fillData(data);
if (mounted) {
setState(() {
dataList = data;
});
}
},
controller: controller,
cursorWidth: 0,
cursorColor: Colors.transparent,
keyboardType: TextInputType.number,
style: TextStyle(color: Colors.transparent),
decoration: InputDecoration(
border: InputBorder.none,
counterText: '',
),
),
],
)
],
),
),
),
);
}
}
複製程式碼
可以上面的效果
自定義車牌號鍵盤
其中第一部分是每個省份的簡寫,之後就是字母和陣列的組合。 使用自定義彈出懸浮窗。這次就不需要使用TextField進行彈出操作,在stack佈局上新增點選方法就可以了。(ps: 資料來源有可能不準確)
Get.dialog(StatefulBuilder(
builder: (context1, setBottomSheetState) {
return UnconstrainedBox(
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.only(
bottom: Get.context.mediaQueryPadding.bottom),
width: Get.width,
decoration: BoxDecoration(
color: Colors.white,
),
child: Wrap(
children: keybordData
.map<Widget>((e) =>
renderNumberOne(e, setBottomSheetState))
.toList(),
)),
);
}),
barrierColor: Colors.transparent,
useRootNavigator: false,
useSafeArea: false);
複製程式碼
自定義鍵盤與資料展示的聯動
下面展示的是點選切換鍵盤效果,主要實現思路是,控制自定義鍵盤內的資料,通過type區分展示不同的資料。
fillData(title) {
if (dataList.length > 7) {
return;
}
List temp = dataList;
int index = -1;
for (int i = 0; i < temp.length; i++) {
if (temp[i] == '' || temp[i] == '新') {
index = i;
break;
}
}
if (index != -1) {
temp[index] = title;
}
setState(() {
dataList = temp;
});
}
renderNumberOne(title, setBottomSheetState) {
return Container(
alignment: Alignment.center,
width: Get.width / 8,
height: Get.width / 8 * 1.2,
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
),
child: Material(
child: InkWell(
onTap: () {
if (type == 0) {
//選擇省份
List temp = dataList;
temp[0] = title;
setBottomSheetState(() {
type = 1;
keybordData = wordList;
});
setState(() {
dataList = temp;
});
} else if (type == 1) {
if (title == '0~9') {
setBottomSheetState(() {
type = 2;
keybordData = numberList;
});
} else {
fillData(title);
}
} else if (type == 2) {
if (title == 'A~Z') {
setBottomSheetState(() {
type = 1;
keybordData = wordList;
});
} else {
fillData(title);
}
}
},
child: title == '刪除'
? Icon(
Icons.delete,
size: 18,
)
: Text(
title,
style: TextStyle(fontSize: 16, color: Colors.black),
),
)),
);
}
複製程式碼
最後就是點選刪除按鈕的邏輯
deleData(title, setBottomSheetState) {
List temp = dataList;
int index = -1;
for (int i = 0; i < temp.length; i++) {
if (temp[i] != '' && temp[i] != '新') {
index = i;
}
}
if (index != -1) {
temp[index] = index == 6 ? '新' : '';
}
if (index == 0) {
setBottomSheetState(() {
type = 1;
keybordData = province;
});
}
setState(() {
dataList = temp;
});
}
複製程式碼
效果:
over~~~