feat: develop base field form item widget
This commit is contained in:
parent
eabb746738
commit
865035e17f
|
@ -15,7 +15,13 @@ class Api {
|
|||
);
|
||||
}
|
||||
|
||||
/// 获取部门信息
|
||||
/// 获取分页角色列表
|
||||
static Future<Response<PaginationData>> getRoles(Map params) {
|
||||
return DioService.dio.get<PaginationData>(Urls.roles,
|
||||
queryParameters: {'page': 1, 'pageSize': 10, ...params});
|
||||
}
|
||||
|
||||
/// 获取部门树
|
||||
static Future<Response> getDepts() {
|
||||
return DioService.dio.get(Urls.depts);
|
||||
}
|
||||
|
|
|
@ -117,6 +117,10 @@ final theme = ThemeData(
|
|||
color: AppTheme.primaryColor,
|
||||
fontSize: ScreenAdaper.height(30),
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
color: AppTheme.grey,
|
||||
fontSize: ScreenAdaper.height(25),
|
||||
),
|
||||
fillColor: AppTheme.inputFillColor,
|
||||
filled: true,
|
||||
labelStyle: TextStyle(
|
||||
|
|
|
@ -17,4 +17,5 @@ class Urls {
|
|||
static String accountMenus = 'account/menus';
|
||||
static String userInfo = 'system/users';
|
||||
static String depts = 'system/depts';
|
||||
static String roles = 'system/roles';
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ class RoleModel {
|
|||
final int? id;
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
final String? name;
|
||||
final String name;
|
||||
final String? value;
|
||||
final String? remark;
|
||||
final int? status;
|
||||
|
|
|
@ -42,7 +42,6 @@ class DeptPicker extends StatelessWidget {
|
|||
}
|
||||
|
||||
Future<List<CascadeItem<int, DeptModel>>> getData() async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
try {
|
||||
final res = await Api.getDepts();
|
||||
if (res.data != null) {
|
||||
|
|
|
@ -5,12 +5,16 @@ import 'package:get/get.dart';
|
|||
import 'package:sk_base_mobile/apis/api.dart';
|
||||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/constants/bg_color.dart';
|
||||
import 'package:sk_base_mobile/models/role.model.dart';
|
||||
import 'package:sk_base_mobile/models/user_info.model.dart';
|
||||
import 'package:sk_base_mobile/screens/hr_manage/components/dept_picker.dart';
|
||||
import 'package:sk_base_mobile/util/logger_util.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_cascade_picker.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_dialog_header.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_multi_picker.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_multi_picker_dialog.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_text_input.dart';
|
||||
import 'package:sk_base_mobile/widgets/gradient_button.dart';
|
||||
|
||||
|
@ -51,6 +55,7 @@ class EditUserInfo extends StatelessWidget {
|
|||
SkTextInput(
|
||||
isDense: true,
|
||||
textController: controller.nameEditController,
|
||||
customLabel: true,
|
||||
labelText: '姓名',
|
||||
),
|
||||
SizedBox(
|
||||
|
@ -60,6 +65,7 @@ class EditUserInfo extends StatelessWidget {
|
|||
/// 部门
|
||||
SkTextInput(
|
||||
isDense: true,
|
||||
customLabel: true,
|
||||
keyboardType: TextInputType.none,
|
||||
textController: controller.deptEditController,
|
||||
labelText: '所属部门',
|
||||
|
@ -74,81 +80,48 @@ class EditUserInfo extends StatelessWidget {
|
|||
),
|
||||
|
||||
/// 角色
|
||||
SkTextInput(
|
||||
SkMultiPickerDropdown(
|
||||
isDense: true,
|
||||
customLabel: true,
|
||||
keyboardType: TextInputType.none,
|
||||
textController: TextEditingController(),
|
||||
textController: controller.roleEditController,
|
||||
labelText: '角色',
|
||||
hint: '选择角色',
|
||||
onTap: (_) async {
|
||||
Get.bottomSheet(Container(
|
||||
height: ScreenAdaper.height(400),
|
||||
decoration:
|
||||
const BoxDecoration(color: AppTheme.nearlyWhite),
|
||||
child: Column(children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: ScreenAdaper.height(20),
|
||||
horizontal: ScreenAdaper.width(20)),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
'确定',
|
||||
style: TextStyle(
|
||||
fontSize: ScreenAdaper.height(30),
|
||||
color: AppTheme.primaryColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: <String>[
|
||||
'角色1',
|
||||
'角色2',
|
||||
'角色3',
|
||||
'角色4',
|
||||
'角色5',
|
||||
'角色6',
|
||||
'角色7',
|
||||
'角色8',
|
||||
'角色9'
|
||||
].map((String text) {
|
||||
return Obx(
|
||||
() => CheckboxListTile(
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: ScreenAdaper.height(0),
|
||||
horizontal: ScreenAdaper.width(20)),
|
||||
title: Text(text),
|
||||
value:
|
||||
controller.selectedDepts.contains(text),
|
||||
onChanged: (bool? value) {
|
||||
if (value == true) {
|
||||
controller.selectedDepts.add(text);
|
||||
} else {
|
||||
controller.selectedDepts.remove(text);
|
||||
Get.bottomSheet(SkMutiPickerDialog(
|
||||
onSelected: (List<PickerItem> selectedData) {
|
||||
controller.roleEditController.text;
|
||||
}, getData: () async {
|
||||
try {
|
||||
final res =
|
||||
await Api.getRoles({'page': 1, 'pageSize': 30});
|
||||
if (res.data != null) {
|
||||
List<PickerItem<int>> result =
|
||||
res.data!.items.map<PickerItem<int>>((e) {
|
||||
RoleModel data = RoleModel.fromJson(e);
|
||||
return PickerItem(
|
||||
label: data.name,
|
||||
value: data.id!,
|
||||
subLabel: data.remark,
|
||||
checked: false);
|
||||
}).toList();
|
||||
return result;
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
))
|
||||
]),
|
||||
));
|
||||
return [];
|
||||
} catch (e) {
|
||||
LoggerUtil().error(e);
|
||||
return [];
|
||||
}
|
||||
})).then(
|
||||
(value) => Get.delete<SkMutiPickerDialogController>());
|
||||
}),
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(defaultPadding),
|
||||
),
|
||||
SkTextInput(
|
||||
isDense: true,
|
||||
textController: TextEditingController(),
|
||||
textController: controller.nickNameEditController,
|
||||
customLabel: true,
|
||||
labelText: '登录用户名',
|
||||
),
|
||||
SizedBox(
|
||||
|
@ -156,9 +129,10 @@ class EditUserInfo extends StatelessWidget {
|
|||
),
|
||||
SkTextInput(
|
||||
isDense: true,
|
||||
customLabel: true,
|
||||
textController: TextEditingController(),
|
||||
labelText: '手机号',
|
||||
)
|
||||
),
|
||||
]),
|
||||
),
|
||||
)),
|
||||
|
@ -271,8 +245,9 @@ class EditUserInfoController extends GetxController {
|
|||
EditUserInfoController(this.userId);
|
||||
final nameEditController = TextEditingController();
|
||||
final deptEditController = TextEditingController();
|
||||
final roleEditController = TextEditingController();
|
||||
final nickNameEditController = TextEditingController();
|
||||
final userInfo = Rxn<UserInfoModel>();
|
||||
RxList selectedDepts = RxList([]);
|
||||
|
||||
@override
|
||||
onReady() {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
abstract class SkBaseFieldWidget extends StatelessWidget {
|
||||
FocusNode focusNode = FocusNode();
|
||||
late SkBaseFieldController baseFieldController;
|
||||
final bool customLabel;
|
||||
final String? labelText;
|
||||
|
||||
SkBaseFieldWidget({
|
||||
super.key,
|
||||
this.customLabel = false,
|
||||
this.labelText,
|
||||
autoFocus = false,
|
||||
}) {
|
||||
baseFieldController = Get.put(
|
||||
SkBaseFieldController(autoFocus: autoFocus, focusNode: focusNode),
|
||||
tag: '${labelText ?? Random().nextInt(1000)}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SkBaseFieldController extends GetxController {
|
||||
RxBool isFocus = false.obs;
|
||||
final bool autoFocus;
|
||||
FocusNode? focusNode;
|
||||
SkBaseFieldController({required this.autoFocus, this.focusNode});
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
if (autoFocus) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
focusNode?.requestFocus();
|
||||
});
|
||||
}
|
||||
focusNode?.addListener(() {
|
||||
isFocus.value = focusNode?.hasFocus ?? false;
|
||||
});
|
||||
super.onReady();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
|
||||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_base_field.dart';
|
||||
|
||||
class SkFormItem extends StatelessWidget {
|
||||
final Widget child;
|
||||
final bool customLabel;
|
||||
final bool isRequired;
|
||||
final String? labelText;
|
||||
final SkBaseFieldController controller;
|
||||
const SkFormItem(
|
||||
{super.key,
|
||||
required this.child,
|
||||
required this.customLabel,
|
||||
required this.controller,
|
||||
this.labelText,
|
||||
this.isRequired = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (customLabel) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (isRequired)
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(
|
||||
color: Colors.red, fontSize: ScreenAdaper.height(25)),
|
||||
),
|
||||
Obx(() => Text(
|
||||
labelText ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: ScreenAdaper.height(25),
|
||||
color: controller.isFocus.value
|
||||
? AppTheme.primaryColor
|
||||
: AppTheme.nearlyBlack),
|
||||
)),
|
||||
]),
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(5),
|
||||
),
|
||||
child
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_base_field.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_form_item.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_tag.dart';
|
||||
import 'package:multi_dropdown/multiselect_dropdown.dart';
|
||||
|
||||
class SkMultiPickerDropdown<T> extends SkBaseFieldWidget {
|
||||
final TextEditingController textController;
|
||||
final Function(FocusNode)? onTap;
|
||||
final bool isRequired;
|
||||
final String? labelText;
|
||||
final String? hint;
|
||||
final bool isTextArea;
|
||||
final bool isDense;
|
||||
final Function(String)? onTapOutside;
|
||||
final Function(String)? onChanged;
|
||||
final String? Function(String?)? validator;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
final ValueChanged<String>? onFieldSubmitted;
|
||||
final Icon? prefix;
|
||||
final Widget? suffixIcon;
|
||||
final InputBorder? border;
|
||||
final FloatingLabelBehavior? floatingLabelBehavior;
|
||||
final TextInputType? keyboardType;
|
||||
SkMultiPickerDropdown(
|
||||
{super.key,
|
||||
required this.textController,
|
||||
super.customLabel = false,
|
||||
super.autoFocus = false,
|
||||
this.onTap,
|
||||
this.hint,
|
||||
this.onFieldSubmitted,
|
||||
this.isRequired = false,
|
||||
this.onTapOutside,
|
||||
this.keyboardType,
|
||||
this.labelText,
|
||||
this.prefix,
|
||||
this.suffixIcon,
|
||||
this.onChanged,
|
||||
this.border,
|
||||
this.floatingLabelBehavior = FloatingLabelBehavior.always,
|
||||
this.isTextArea = false,
|
||||
this.contentPadding,
|
||||
this.isDense = false,
|
||||
this.validator});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SkFormItem(
|
||||
child: MultiSelectDropDown<int>(
|
||||
focusNode: focusNode,
|
||||
onOptionSelected: (List<ValueItem> selectedOptions) {},
|
||||
options: <ValueItem<int>>[
|
||||
ValueItem(label: 'Option 1', value: 1),
|
||||
ValueItem(label: 'Option 2', value: 2),
|
||||
ValueItem(label: 'Option 3', value: 3),
|
||||
ValueItem(label: 'Option 4', value: 4),
|
||||
ValueItem(label: 'Option 5', value: 5),
|
||||
ValueItem(label: 'Option 6', value: 6),
|
||||
],
|
||||
borderColor: AppTheme.nearlyBlack,
|
||||
fieldBackgroundColor: AppTheme.inputFillColor,
|
||||
borderWidth: 1,
|
||||
borderRadius: ScreenAdaper.sp(15),
|
||||
focusedBorderWidth: 2,
|
||||
focusedBorderColor: AppTheme.primaryColorLight,
|
||||
hint: '请选择',
|
||||
hintStyle: Theme.of(Get.context!).inputDecorationTheme.hintStyle,
|
||||
hintPadding: EdgeInsets.symmetric(horizontal: ScreenAdaper.width(5)),
|
||||
selectionType: SelectionType.multi,
|
||||
chipConfig: const ChipConfig(wrapType: WrapType.scroll),
|
||||
optionTextStyle: const TextStyle(fontSize: 16),
|
||||
selectedOptionIcon: const Icon(Icons.check_circle),
|
||||
),
|
||||
customLabel: customLabel,
|
||||
labelText: labelText,
|
||||
isRequired: isRequired,
|
||||
controller: baseFieldController);
|
||||
|
||||
// return DropdownButtonFormField<String>(
|
||||
// focusNode: focusNode,
|
||||
// onTap: () {
|
||||
// if (widget.onTap != null) {
|
||||
// widget.onTap!(focusNode);
|
||||
// }
|
||||
// },
|
||||
// icon: Icon(Icons.arrow_drop_down),
|
||||
// selectedItemBuilder: (context) => [
|
||||
// Container(
|
||||
// width: ScreenAdaper.width(200),
|
||||
// child: SingleChildScrollView(
|
||||
// scrollDirection: Axis.horizontal,
|
||||
// child: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// SkTag(text: '角色', color: AppTheme.primaryColor),
|
||||
// ]),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
// decoration: InputDecoration(
|
||||
// prefixIcon: widget.prefix,
|
||||
// errorStyle: const TextStyle(fontSize: 0, height: 0.01),
|
||||
// contentPadding: widget.contentPadding,
|
||||
// isDense: widget.isDense,
|
||||
// border: widget.border,
|
||||
// floatingLabelBehavior: widget.floatingLabelBehavior,
|
||||
// label: widget.labelText != null
|
||||
// ? Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
// mainAxisSize: MainAxisSize.min,
|
||||
// children: [
|
||||
// if (widget.isRequired)
|
||||
// Text(
|
||||
// "*",
|
||||
// style: TextStyle(
|
||||
// color: Colors.red,
|
||||
// fontSize: ScreenAdaper.height(30)),
|
||||
// ),
|
||||
// Text(
|
||||
// widget.labelText!,
|
||||
// style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
||||
// ),
|
||||
// ])
|
||||
// : null,
|
||||
// focusedBorder: OutlineInputBorder(
|
||||
// borderSide:
|
||||
// const BorderSide(color: AppTheme.primaryColorLight, width: 2),
|
||||
// borderRadius: BorderRadius.circular(ScreenAdaper.sp(15))),
|
||||
// hintText: widget.hint ?? '请输入',
|
||||
// ),
|
||||
// items: [],
|
||||
// onChanged: (Object? value) {},
|
||||
// );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
||||
import 'package:sk_base_mobile/widgets/loading_indicator.dart';
|
||||
|
||||
class SkMutiPickerDialog<T> extends StatelessWidget {
|
||||
final SkMutiPickerDialogController controller;
|
||||
Function(List<PickerItem> data)? onSelected;
|
||||
SkMutiPickerDialog(
|
||||
{super.key,
|
||||
required Future<List<PickerItem<T>>> Function() getData,
|
||||
this.onSelected})
|
||||
: controller = Get.put(SkMutiPickerDialogController<T>(getData: getData));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: ScreenAdaper.height(400),
|
||||
decoration: const BoxDecoration(color: AppTheme.nearlyWhite),
|
||||
child: Column(children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: ScreenAdaper.height(20),
|
||||
horizontal: ScreenAdaper.width(20)),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'取消',
|
||||
style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (onSelected != null) {
|
||||
final selectedData = controller.pickData
|
||||
.where((element) => element.checked)
|
||||
.toList();
|
||||
if (selectedData.isEmpty) {
|
||||
SnackBarUtil().warning('请最少选择一个“员工”角色作为基础角色');
|
||||
return;
|
||||
}
|
||||
onSelected!(selectedData);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
'确定',
|
||||
style: TextStyle(
|
||||
fontSize: ScreenAdaper.height(30),
|
||||
color: AppTheme.primaryColor),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => controller.loading.value
|
||||
? const LoadingIndicator(
|
||||
common: true,
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: controller.pickData.mapIndexed((
|
||||
int index,
|
||||
PickerItem item,
|
||||
) {
|
||||
return CheckboxListTile(
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>(
|
||||
(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return AppTheme.primaryColor;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
dense: true,
|
||||
visualDensity: VisualDensity.compact,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: ScreenAdaper.height(0),
|
||||
horizontal: ScreenAdaper.width(20)),
|
||||
title: Text(item.label,
|
||||
style: TextStyle(fontSize: ScreenAdaper.height(25))),
|
||||
subtitle: item.subLabel == null
|
||||
? null
|
||||
: Text(
|
||||
item.subLabel!,
|
||||
style: TextStyle(
|
||||
fontSize: ScreenAdaper.height(20),
|
||||
color: AppTheme.grey),
|
||||
),
|
||||
value: controller.pickData[index].checked,
|
||||
onChanged: (bool? value) {
|
||||
PickerItem item = controller.pickData[index];
|
||||
item.checked = value ?? false;
|
||||
controller.pickData[index] = item;
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
)),
|
||||
))
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SkMutiPickerDialogController<T> extends GetxController {
|
||||
RxList<PickerItem<T>> pickData = RxList([]);
|
||||
Future<List<PickerItem<T>>> Function() getData;
|
||||
SkMutiPickerDialogController({required this.getData});
|
||||
RxBool loading = false.obs;
|
||||
@override
|
||||
void onReady() {
|
||||
init();
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
loading.value = true;
|
||||
pickData.assignAll(await getData());
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
class PickerItem<T> {
|
||||
final String label;
|
||||
final String? subLabel;
|
||||
final T value;
|
||||
bool checked;
|
||||
PickerItem(
|
||||
{required this.label,
|
||||
required this.value,
|
||||
required this.checked,
|
||||
this.subLabel});
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_base_field.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_form_item.dart';
|
||||
|
||||
class SkTextInput extends StatefulWidget {
|
||||
class SkTextInput extends SkBaseFieldWidget {
|
||||
final TextEditingController textController;
|
||||
final Function(FocusNode)? onTap;
|
||||
final bool isRequired;
|
||||
final String? labelText;
|
||||
|
||||
final String? hint;
|
||||
final bool isTextArea;
|
||||
final bool isDense;
|
||||
|
@ -14,15 +15,19 @@ class SkTextInput extends StatefulWidget {
|
|||
final Function(String)? onChanged;
|
||||
final String? Function(String?)? validator;
|
||||
final EdgeInsetsGeometry? contentPadding;
|
||||
final bool autoFocus;
|
||||
|
||||
final ValueChanged<String>? onFieldSubmitted;
|
||||
final Icon? prefix;
|
||||
final Widget? suffixIcon;
|
||||
final InputBorder? border;
|
||||
final FloatingLabelBehavior? floatingLabelBehavior;
|
||||
final TextInputType? keyboardType;
|
||||
const SkTextInput(
|
||||
|
||||
SkTextInput(
|
||||
{super.key,
|
||||
super.customLabel = false,
|
||||
super.autoFocus = false,
|
||||
super.labelText,
|
||||
required this.textController,
|
||||
this.onTap,
|
||||
this.hint,
|
||||
|
@ -30,76 +35,57 @@ class SkTextInput extends StatefulWidget {
|
|||
this.isRequired = false,
|
||||
this.onTapOutside,
|
||||
this.keyboardType,
|
||||
this.labelText,
|
||||
this.prefix,
|
||||
this.suffixIcon,
|
||||
this.onChanged,
|
||||
this.border,
|
||||
this.floatingLabelBehavior = FloatingLabelBehavior.always,
|
||||
this.isTextArea = false,
|
||||
this.autoFocus = false,
|
||||
this.contentPadding,
|
||||
this.isDense = false,
|
||||
this.validator});
|
||||
|
||||
@override
|
||||
State<SkTextInput> createState() => _SkTextInputState();
|
||||
}
|
||||
|
||||
class _SkTextInputState extends State<SkTextInput> {
|
||||
late FocusNode focusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.autoFocus) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
focusNode.requestFocus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
Widget field = TextFormField(
|
||||
focusNode: focusNode,
|
||||
controller: widget.textController,
|
||||
controller: textController,
|
||||
onChanged: (String value) {
|
||||
if (widget.onChanged != null) {
|
||||
widget.onChanged!(value);
|
||||
if (onChanged != null) {
|
||||
onChanged!(value);
|
||||
}
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
if (widget.onTapOutside != null) {
|
||||
widget.onTapOutside!(widget.textController.text);
|
||||
if (onTapOutside != null) {
|
||||
onTapOutside!(textController.text);
|
||||
FocusScope.of(context).unfocus();
|
||||
}
|
||||
},
|
||||
maxLines: widget.isTextArea ? 2 : 1, // 添加这行代码
|
||||
maxLines: isTextArea ? 2 : 1, // 添加这行代码
|
||||
onTap: () {
|
||||
if (widget.onTap != null) {
|
||||
widget.onTap!(focusNode);
|
||||
if (onTap != null) {
|
||||
onTap!(focusNode);
|
||||
}
|
||||
},
|
||||
keyboardType: widget.keyboardType,
|
||||
onFieldSubmitted: widget.onFieldSubmitted,
|
||||
keyboardType: keyboardType,
|
||||
onFieldSubmitted: onFieldSubmitted,
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
validator: widget.validator,
|
||||
validator: validator,
|
||||
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: widget.prefix,
|
||||
suffixIcon: widget.suffixIcon,
|
||||
prefixIcon: prefix,
|
||||
suffixIcon: suffixIcon,
|
||||
errorStyle: const TextStyle(fontSize: 0, height: 0.01),
|
||||
contentPadding: widget.contentPadding,
|
||||
isDense: widget.isDense,
|
||||
border: widget.border,
|
||||
floatingLabelBehavior: widget.floatingLabelBehavior,
|
||||
label: widget.labelText != null
|
||||
contentPadding: contentPadding,
|
||||
isDense: isDense,
|
||||
border: border,
|
||||
floatingLabelBehavior: floatingLabelBehavior,
|
||||
label: labelText != null && !customLabel
|
||||
? Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.isRequired)
|
||||
if (isRequired)
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(
|
||||
|
@ -107,16 +93,28 @@ class _SkTextInputState extends State<SkTextInput> {
|
|||
fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
Text(
|
||||
widget.labelText!,
|
||||
labelText!,
|
||||
style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
])
|
||||
: null,
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: AppTheme.primaryColorLight, width: 2),
|
||||
borderRadius: BorderRadius.circular(ScreenAdaper.sp(15))),
|
||||
hintText: widget.hint ?? '请输入',
|
||||
hintText: hint ?? '请输入',
|
||||
),
|
||||
);
|
||||
return SkFormItem(
|
||||
controller: baseFieldController,
|
||||
customLabel: customLabel,
|
||||
labelText: labelText,
|
||||
isRequired: isRequired,
|
||||
child: field,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// class SkTextInputController extends GetxController {
|
||||
// RxBool isFocus = false.obs;
|
||||
// @override
|
||||
// void onReady() {
|
||||
// super.onReady();
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -608,6 +608,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
multi_dropdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: multi_dropdown
|
||||
sha256: b63ff339fcc875d667f8688c8ef62853545b580dd2b6fe78b73339783268afd8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -68,6 +68,7 @@ dependencies:
|
|||
math_expressions: ^2.4.0
|
||||
install_plugin: ^2.1.0
|
||||
url_launcher: ^6.2.5
|
||||
multi_dropdown: ^2.1.4
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|
Loading…
Reference in New Issue