版權聲明:本文為本人原創文章,未經本人允許不得轉載。
上次我們完成了首頁項目展示的基本工作,但是展示的內容都是我們預先寫好的,今天我們就來說一說如何獲取用戶的輸入來進行數據展示
廢話不多說,我們正式開始。還記得首頁底部有個添加符號的按鈕吧,我們就是通過這個按鈕來進入到新增項目信息的頁面DiyAddDialog的。
下面我們開始繪制這個頁面需要展示的UI,因為是獲取用戶輸入,那么這個頁面基本可以得知都是一些與用戶進行交互的控件,比如日期選擇器、文本輸入、照片獲取等等。
老規矩先看下基本效果:
分析上圖結構,我們可以看出一共需要用到以下幾種控件:
1.日期選擇器
2.文本輸入控件
3.圖片選擇器
下面我們分別實現這些控件的顯示,當然了這次實際寫完的效果可能與上圖有出入,因為女王大人給了新的要求,要增加一些內容,所以我會重新規劃布局,但是只要你掌握了方法,其他都是一樣的。
1.時間選擇器
因為時間選擇器比較獨立,同時可能出現在不同的地方都會使用,所以我們單獨寫這個時間選擇器控件。
在model文件夾下新建date_format.dart文件,在文件中編寫日期選擇器控件。
因為涉及到日期格式化,所以我們這里需要用到第三方插件包,在整個教程中這里是第一次涉及,所以我放一個中文官方文檔鏈接,里面詳細說明了如何使用第三方插件包:https://flutterchina.club/using-packages/#%E6%90%9C%E7%B4%A2packages。
我們這里要用到的是國際化支持的 intl 包,代碼如下:
date_format.dart
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class DatePicker extends StatelessWidget {
DatePicker({Key key, this.selectedDate, this.selectDate}) : super(key: key);
//已經選擇的時間
final DateTime selectedDate;
//泛型是時間的改變回調函數,當選擇時間改變后觸發
final ValueChanged<DateTime> selectDate;
//選擇時間方法
_datePicker(BuildContext context) async {
DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2015, 8),
lastDate: DateTime(2050),
);
if (picked != null) {
selectDate(picked);
}
}
@override
Widget build(BuildContext context) {
return new ListTile(
title: new InkWell(
onTap: () => _datePicker(context),
child: new Row(
children: <Widget>[
new Icon(Icons.today),
new SizedBox(
width: 20.0,
),
new Text(DateFormat.yMd("en_US").format(selectedDate)),
],
),
),
);
}
}
以上代碼中,showDatePicker是material材質的安卓日期選擇器,返回的是一個將來的時間,所以這里需要用到異步操作。如果有不明白異步的同學可以去了解下簡單的異步知識,我也只是了解基本的異步使用。
時間選擇器我們寫完了,要把時間選擇器放到頁面上,下一步我們在ui文件夾下繼續新建diy_add_show.dart,用于存放新增項目頁面的ui布局代碼。
diy_add_show.dart
import 'package:activity_record/model/date_format.dart';
import 'package:flutter/material.dart';
class DiyAddShow extends StatefulWidget {
@override
State<StatefulWidget> createState() => new DiyAddShowState();
}
class DiyAddShowState extends State<DiyAddShow> {
//實例化對象已選擇的時間,并賦予初始值是當前時間
DateTime _selectedDate = DateTime.now();
@override
Widget build(BuildContext context) {
//safeArea是安全區域小控件,通過足夠的填充來保護其子控件,以避免顯示內容被系統級元素覆蓋或出現異常。
return new SafeArea(
top: false,
bottom: false,
child: new ListView(
children: <Widget>[
new DatePicker(
selectedDate: _selectedDate,
selectDate: (DateTime date) {
setState(() {
_selectedDate = date;
});
},
)
],
),
);
}
}
然后我們回到DiyAddDialog.dart,文件,修改body部分內容,把新增項目的ui放進去:
diy_add_dialog.dart
import 'package:activity_record/ui/diy_add_show.dart';
import 'package:flutter/material.dart';
/*
diy活動新增頁面
涉及用戶輸入所以繼承自狀態可變的StatefulWidget
采用全屏對話框的形式展現
*/
class DiyAddDialog extends StatefulWidget {
@override
DiyAddDialogState createState() => new DiyAddDialogState();
}
class DiyAddDialogState extends State<DiyAddDialog> {
final _title = '新增活動';
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(_title),
),
body: new DiyAddShow(),//新增項目的UI
);
}
}
終于到看成果的時候了,程序跑起來,點擊首頁底部的添加按鈕,看下效果:
頂部出現了我們的日期顯示,默認是當前時間,當然顯示格式大家可以根據需求進行調整。
當點擊日期后,會彈出時間選擇器就可以修改時間了:
以上這個是安卓材質的時間選擇器,flutter倉庫包里還有諸如ios風格的時間選擇器,比如 flutter_cupertino_date_picker,大家可以嘗試著把上面的時間選擇器換成ios風格的。
2.文本輸入框
文本輸入框的控件相對其實比較簡單,主要就是TextField控件來實現用戶輸入,而TextField里有個獲取用戶輸入信息的控制器,添加他們
在diy_add_show.dart文件里添加各個輸入框的控制器用于獲取用戶輸入的值:
diy_add_show.dart
//活動名稱輸入框控制器
TextEditingController _nameTextEditingController =
new TextEditingController();
//活動地點輸入框控制器
TextEditingController _placeTextEditingController =
new TextEditingController();
//活動聯系人輸入框控制器
TextEditingController _contactTextEditingController =
new TextEditingController();
//活動單價輸入框控制器
TextEditingController _singlePriceTextEditingController =
new TextEditingController();
//活動份數輸入框控制器
TextEditingController _numsTextEditingController =
new TextEditingController();
//活動物料成本輸入框控制器
TextEditingController _itemCostTextEditingController =
new TextEditingController();
//活動人員成本輸入框控制器
TextEditingController _laborCostTextEditingController =
new TextEditingController();
然后我們先添加活動基本信息的輸入框:
//活動文字信息輸入
Widget _infoTextField(
IconData icon, TextEditingController controller, String hint) {
return Padding(
padding: const EdgeInsets.fromLTRB(18.0, 10.0, 18.0, 0.0),
child: new TextField(
autofocus: true,
controller: controller,
//這個文本框的裝飾包含了一個圖標和提示文字
decoration: new InputDecoration(icon: new Icon(icon), hintText: hint),
),
);
}
然后添加金額數字輸入框:
//活動價格份數信息輸入框封裝
Widget _amountTextField(TextEditingController controller, String labelText,
String prefixText, String suffixText) {
return new TextField(
//鍵盤類型適用于登錄的
keyboardType: TextInputType.numberWithOptions(signed: true),
controller: controller,
/*
輸入框裝飾:
包含邊框、標題、提示文本、后綴文本
*/
decoration: new InputDecoration(
border: OutlineInputBorder(),
labelText: labelText,
prefixText: prefixText,
suffixText: suffixText,
suffixStyle: new TextStyle(color: Colors.green)),
);
}
不同的輸入框我們已經封裝寫完,最后就是根據自己的設計習慣將他們擺放在頁面上展示出來,我們繼續在DiyAddShow.dart
中日期選擇器的下面把輸入框組合起來,完成最后的展示:
_infoTextField(Icons.spa, _nameTextEditingController, '活動名稱'),
_infoTextField(
Icons.my_location, _placeTextEditingController, '活動地點'),
_infoTextField(
Icons.tag_faces, _contactTextEditingController, '聯系人'),
//把兩個金額輸入框放在一個包含padding的橫向布局里
new Padding(
padding: const EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0.0),
child: new Row(
children: <Widget>[
new Expanded(
child: _amountTextField(_singlePriceTextEditingController,
'活動單價', '\¥', 'CNY'),
),
new SizedBox(
width: 10.0,
),
new Expanded(
child: _amountTextField(
_numsTextEditingController, '活動份數', '\@', '份'),
),
],
),
),
//把兩個金額輸入框放在一個包含padding的橫向布局里
new Padding(
padding: const EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0.0),
child: new Row(
children: <Widget>[
new Expanded(
child: _amountTextField(
_itemCostTextEditingController, '物料成本', '\¥', 'CNY'),
),
new SizedBox(
width: 10.0,
),
new Expanded(
child: _amountTextField(
_laborCostTextEditingController, '人員成本', '\¥', 'CNY'),
),
],
),
),
到這里基本新增項目的頁面UI就基本實現了,趕緊跑起來看看效果吧:
3.圖片選擇器
flutter支持不同方式顯示圖片,比如網絡、本地、緩存等等,但是默認好像是沒有從相冊選擇圖片的,所以這里就需要用到第三方插件包:image_picker: ^0.4.10,使用方法在上面貼過教程鏈接,這里就不再介紹如何使用。
在diy_add_show.dart
文件中添加如下代碼:
String _imagePath;
//從本地相冊選擇圖片
Future _getImagePath() async {
File file = await ImagePicker.pickImage(source: ImageSource.gallery);
if (file != null) {
setState(() {
_imagePath = file.path;
});
}
}
以上代碼就是通過圖像選擇器插件從相冊選取,并獲得圖片的本地路徑。以后數據庫保存的時候不是直接保存圖片,而是保存圖片的地址,所以這里我們預先獲得圖片路徑。其中ImageSource.gallery改成ImageSource.camera就可以調用攝像頭拍照了。
我們繼續在金額輸入框下面添加展示照片的控件,代碼如下:
new Padding(
padding: const EdgeInsets.all(18.0),
child: new SizedBox(
height: 120.0,
child: new Container(
decoration: new BoxDecoration(
border: new Border.all(color: Colors.grey),
borderRadius: new BorderRadius.circular(5.0)),
child: new InkWell(
onTap: () => _getImagePath(),
child: _image == null
? new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Icon(Icons.photo,size: 40.0,color: Theme.of(context).primaryColor,),
new Text('從相冊選取圖片')
],
)
//Image.file是根據路徑獲得圖片
: new Image.file(
File(_imagePath),
fit: BoxFit.cover,
),
),
)),
),
以上代碼顯示一個120高度的容器,如果圖片還未選擇,那么顯示一個圖標和選取圖片的文字提示,如果選取了那么直接顯示圖片。
運行程序看下效果,沒有選擇圖片之前:
點擊從相冊選取后:
本文總結
通過本文,我想你應該掌握了日期選擇器、文本輸入框、圖片選擇器的使用,并對上篇文章介紹的控件之間組合布局有了更深的了解,使用起來肯定更加熟練了。
下次我們將開始介紹頁面之間的數據傳送。
最后附上項目源碼地址:https://gitee.com/xusujun33/activity_record_jia.git
項目持續更新中.......