From 8b2067fe18492988d1d2341cb176ca5bf8fcf526 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 24 Sep 2024 18:54:57 +0800 Subject: [PATCH 01/25] =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=BC=80=E5=A7=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/base/intl_resource_delegate.dart | 2 +- tdesign-component/example/lib/config.dart | 3 + .../lib/gen_l10n/app_localizations.dart | 391 ++++++++++++++++++ .../lib/gen_l10n/app_localizations_en.dart | 138 +++++++ .../lib/gen_l10n/app_localizations_zh.dart | 138 +++++++ tdesign-component/example/lib/home.dart | 4 +- tdesign-component/example/lib/main.dart | 2 +- .../example/lib/page/td_form_page.dart | 188 +++++++++ tdesign-component/example/pubspec.lock | 202 ++++++++- .../lib/src/components/form/td_form.dart | 0 .../lib/src/components/form/td_form_item.dart | 21 + tdesign-component/pubspec.lock | 288 +++++++++++-- tdesign-component/pubspec.yaml | 1 + tdesign-site/package-lock.json | 7 +- tdesign-site/package.json | 5 +- 15 files changed, 1358 insertions(+), 32 deletions(-) create mode 100644 tdesign-component/example/lib/gen_l10n/app_localizations.dart create mode 100644 tdesign-component/example/lib/gen_l10n/app_localizations_en.dart create mode 100644 tdesign-component/example/lib/gen_l10n/app_localizations_zh.dart create mode 100644 tdesign-component/example/lib/page/td_form_page.dart create mode 100644 tdesign-component/lib/src/components/form/td_form.dart create mode 100644 tdesign-component/lib/src/components/form/td_form_item.dart diff --git a/tdesign-component/example/lib/base/intl_resource_delegate.dart b/tdesign-component/example/lib/base/intl_resource_delegate.dart index 0b5eb9c98..5ea23f097 100644 --- a/tdesign-component/example/lib/base/intl_resource_delegate.dart +++ b/tdesign-component/example/lib/base/intl_resource_delegate.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../gen_l10n/app_localizations.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; /// 国际化资源代理 diff --git a/tdesign-component/example/lib/config.dart b/tdesign-component/example/lib/config.dart index fa515e92c..d835d332d 100644 --- a/tdesign-component/example/lib/config.dart +++ b/tdesign-component/example/lib/config.dart @@ -29,6 +29,7 @@ import 'page/td_icon_page.dart'; import 'page/td_image_page.dart'; import 'page/td_image_viewer_page.dart'; import 'page/td_input_page.dart'; +import 'page/td_form_page.dart'; import 'page/td_link_page.dart'; import 'page/td_loading_page.dart'; import 'page/td_navbar_page.dart'; @@ -120,6 +121,8 @@ Map> exampleMap = { name: 'date-time-picker', pageName: 'data_picker', pageBuilder: _wrapInheritedTheme((context) => const TDDatePickerPage())), + ExamplePageModel( + text: 'Form 表单', name: 'form', pageBuilder: _wrapInheritedTheme((context) => const TDFormPage())), ExamplePageModel( text: 'Input 输入框', name: 'input', pageBuilder: _wrapInheritedTheme((context) => const TDInputViewPage())), ExamplePageModel( diff --git a/tdesign-component/example/lib/gen_l10n/app_localizations.dart b/tdesign-component/example/lib/gen_l10n/app_localizations.dart new file mode 100644 index 000000000..605cf7aea --- /dev/null +++ b/tdesign-component/example/lib/gen_l10n/app_localizations.dart @@ -0,0 +1,391 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_en.dart'; +import 'app_localizations_zh.dart'; + +/// Callers can lookup localized strings with an instance of AppLocalizations +/// returned by `AppLocalizations.of(context)`. +/// +/// Applications need to include `AppLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'gen_l10n/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocalizations.localizationsDelegates, +/// supportedLocales: AppLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocalizations.supportedLocales +/// property. +abstract class AppLocalizations { + AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocalizations? of(BuildContext context) { + return Localizations.of(context, AppLocalizations); + } + + static const LocalizationsDelegate delegate = _AppLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('en'), + Locale('zh') + ]; + + /// No description provided for @components. + /// + /// In en, this message translates to: + /// **'TD Flutter Components'** + String get components; + + /// No description provided for @about. + /// + /// In en, this message translates to: + /// **'About'** + String get about; + + /// No description provided for @defaultTheme. + /// + /// In en, this message translates to: + /// **'defaultTheme'** + String get defaultTheme; + + /// No description provided for @greenTheme. + /// + /// In en, this message translates to: + /// **'greenTheme'** + String get greenTheme; + + /// No description provided for @redTheme. + /// + /// In en, this message translates to: + /// **'redTheme'** + String get redTheme; + + /// No description provided for @cancel. + /// + /// In en, this message translates to: + /// **'cancel'** + String get cancel; + + /// No description provided for @confirm. + /// + /// In en, this message translates to: + /// **'confirm'** + String get confirm; + + /// No description provided for @switchClose. + /// + /// In en, this message translates to: + /// **'C'** + String get switchClose; + + /// No description provided for @switchOpen. + /// + /// In en, this message translates to: + /// **'O'** + String get switchOpen; + + /// No description provided for @knew. + /// + /// In en, this message translates to: + /// **'knew'** + String get knew; + + /// No description provided for @loading. + /// + /// In en, this message translates to: + /// **'loading'** + String get loading; + + /// No description provided for @loadingWithPoint. + /// + /// In en, this message translates to: + /// **'loading...'** + String get loadingWithPoint; + + /// No description provided for @other. + /// + /// In en, this message translates to: + /// **'other'** + String get other; + + /// No description provided for @refreshing. + /// + /// In en, this message translates to: + /// **'refreshing'** + String get refreshing; + + /// No description provided for @releaseRefresh. + /// + /// In en, this message translates to: + /// **'releaseRefresh'** + String get releaseRefresh; + + /// No description provided for @reset. + /// + /// In en, this message translates to: + /// **'reset'** + String get reset; + + /// No description provided for @days. + /// + /// In en, this message translates to: + /// **'days'** + String get days; + + /// No description provided for @hours. + /// + /// In en, this message translates to: + /// **'hours'** + String get hours; + + /// No description provided for @minutes. + /// + /// In en, this message translates to: + /// **'minutes'** + String get minutes; + + /// No description provided for @seconds. + /// + /// In en, this message translates to: + /// **'seconds'** + String get seconds; + + /// No description provided for @milliseconds. + /// + /// In en, this message translates to: + /// **'milliseconds'** + String get milliseconds; + + /// No description provided for @sunday. + /// + /// In en, this message translates to: + /// **'SUN'** + String get sunday; + + /// No description provided for @monday. + /// + /// In en, this message translates to: + /// **'MON'** + String get monday; + + /// No description provided for @tuesday. + /// + /// In en, this message translates to: + /// **'TUE'** + String get tuesday; + + /// No description provided for @wednesday. + /// + /// In en, this message translates to: + /// **'WED'** + String get wednesday; + + /// No description provided for @thursday. + /// + /// In en, this message translates to: + /// **'THU'** + String get thursday; + + /// No description provided for @friday. + /// + /// In en, this message translates to: + /// **'FRI'** + String get friday; + + /// No description provided for @saturday. + /// + /// In en, this message translates to: + /// **'SAT'** + String get saturday; + + /// No description provided for @year. + /// + /// In en, this message translates to: + /// **''** + String get year; + + /// No description provided for @january. + /// + /// In en, this message translates to: + /// **'January'** + String get january; + + /// No description provided for @february. + /// + /// In en, this message translates to: + /// **'February'** + String get february; + + /// No description provided for @march. + /// + /// In en, this message translates to: + /// **'March'** + String get march; + + /// No description provided for @april. + /// + /// In en, this message translates to: + /// **'April'** + String get april; + + /// No description provided for @may. + /// + /// In en, this message translates to: + /// **'May'** + String get may; + + /// No description provided for @june. + /// + /// In en, this message translates to: + /// **'June'** + String get june; + + /// No description provided for @july. + /// + /// In en, this message translates to: + /// **'July'** + String get july; + + /// No description provided for @august. + /// + /// In en, this message translates to: + /// **'August'** + String get august; + + /// No description provided for @september. + /// + /// In en, this message translates to: + /// **'September'** + String get september; + + /// No description provided for @october. + /// + /// In en, this message translates to: + /// **'October'** + String get october; + + /// No description provided for @november. + /// + /// In en, this message translates to: + /// **'November'** + String get november; + + /// No description provided for @december. + /// + /// In en, this message translates to: + /// **'December'** + String get december; + + /// No description provided for @time. + /// + /// In en, this message translates to: + /// **'Time'** + String get time; + + /// No description provided for @start. + /// + /// In en, this message translates to: + /// **'Start'** + String get start; + + /// No description provided for @end. + /// + /// In en, this message translates to: + /// **'End'** + String get end; +} + +class _AppLocalizationsDelegate extends LocalizationsDelegate { + const _AppLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocalizationsDelegate old) => false; +} + +AppLocalizations lookupAppLocalizations(Locale locale) { + + + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': return AppLocalizationsEn(); + case 'zh': return AppLocalizationsZh(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.' + ); +} diff --git a/tdesign-component/example/lib/gen_l10n/app_localizations_en.dart b/tdesign-component/example/lib/gen_l10n/app_localizations_en.dart new file mode 100644 index 000000000..3ab94e7c4 --- /dev/null +++ b/tdesign-component/example/lib/gen_l10n/app_localizations_en.dart @@ -0,0 +1,138 @@ +import 'app_localizations.dart'; + +/// The translations for English (`en`). +class AppLocalizationsEn extends AppLocalizations { + AppLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get components => 'TD Flutter Components'; + + @override + String get about => 'About'; + + @override + String get defaultTheme => 'defaultTheme'; + + @override + String get greenTheme => 'greenTheme'; + + @override + String get redTheme => 'redTheme'; + + @override + String get cancel => 'cancel'; + + @override + String get confirm => 'confirm'; + + @override + String get switchClose => 'C'; + + @override + String get switchOpen => 'O'; + + @override + String get knew => 'knew'; + + @override + String get loading => 'loading'; + + @override + String get loadingWithPoint => 'loading...'; + + @override + String get other => 'other'; + + @override + String get refreshing => 'refreshing'; + + @override + String get releaseRefresh => 'releaseRefresh'; + + @override + String get reset => 'reset'; + + @override + String get days => 'days'; + + @override + String get hours => 'hours'; + + @override + String get minutes => 'minutes'; + + @override + String get seconds => 'seconds'; + + @override + String get milliseconds => 'milliseconds'; + + @override + String get sunday => 'SUN'; + + @override + String get monday => 'MON'; + + @override + String get tuesday => 'TUE'; + + @override + String get wednesday => 'WED'; + + @override + String get thursday => 'THU'; + + @override + String get friday => 'FRI'; + + @override + String get saturday => 'SAT'; + + @override + String get year => ''; + + @override + String get january => 'January'; + + @override + String get february => 'February'; + + @override + String get march => 'March'; + + @override + String get april => 'April'; + + @override + String get may => 'May'; + + @override + String get june => 'June'; + + @override + String get july => 'July'; + + @override + String get august => 'August'; + + @override + String get september => 'September'; + + @override + String get october => 'October'; + + @override + String get november => 'November'; + + @override + String get december => 'December'; + + @override + String get time => 'Time'; + + @override + String get start => 'Start'; + + @override + String get end => 'End'; +} diff --git a/tdesign-component/example/lib/gen_l10n/app_localizations_zh.dart b/tdesign-component/example/lib/gen_l10n/app_localizations_zh.dart new file mode 100644 index 000000000..bb77f6c00 --- /dev/null +++ b/tdesign-component/example/lib/gen_l10n/app_localizations_zh.dart @@ -0,0 +1,138 @@ +import 'app_localizations.dart'; + +/// The translations for Chinese (`zh`). +class AppLocalizationsZh extends AppLocalizations { + AppLocalizationsZh([String locale = 'zh']) : super(locale); + + @override + String get components => 'TDesign Flutter 组件库'; + + @override + String get about => '关于'; + + @override + String get defaultTheme => '默认主题'; + + @override + String get greenTheme => '绿色主题'; + + @override + String get redTheme => '红色主题'; + + @override + String get cancel => '取消'; + + @override + String get confirm => '确认'; + + @override + String get switchClose => '关'; + + @override + String get switchOpen => '开'; + + @override + String get knew => '知道了'; + + @override + String get loading => '加载中'; + + @override + String get loadingWithPoint => '加载中...'; + + @override + String get other => '其它'; + + @override + String get refreshing => '正在刷新'; + + @override + String get releaseRefresh => '松开刷新'; + + @override + String get reset => '重置'; + + @override + String get days => '天'; + + @override + String get hours => '时'; + + @override + String get minutes => '分'; + + @override + String get seconds => '秒'; + + @override + String get milliseconds => '毫秒'; + + @override + String get sunday => '日'; + + @override + String get monday => '一'; + + @override + String get tuesday => '二'; + + @override + String get wednesday => '三'; + + @override + String get thursday => '四'; + + @override + String get friday => '五'; + + @override + String get saturday => '六'; + + @override + String get year => ' 年'; + + @override + String get january => '1 月'; + + @override + String get february => '2 月'; + + @override + String get march => '3 月'; + + @override + String get april => '4 月'; + + @override + String get may => '5 月'; + + @override + String get june => '6 月'; + + @override + String get july => '7 月'; + + @override + String get august => '8 月'; + + @override + String get september => '9 月'; + + @override + String get october => '10 月'; + + @override + String get november => '11 月'; + + @override + String get december => '12 月'; + + @override + String get time => '时间'; + + @override + String get start => '开始'; + + @override + String get end => '结束'; +} diff --git a/tdesign-component/example/lib/home.dart b/tdesign-component/example/lib/home.dart index e28808419..b42ac630c 100644 --- a/tdesign-component/example/lib/home.dart +++ b/tdesign-component/example/lib/home.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:tdesign_flutter/src/util/log.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; - +import 'gen_l10n/app_localizations.dart'; import 'base/example_base.dart'; import 'base/example_route.dart'; import 'base/web_md_tool.dart'; diff --git a/tdesign-component/example/lib/main.dart b/tdesign-component/example/lib/main.dart index 763298943..c05d0d502 100644 --- a/tdesign-component/example/lib/main.dart +++ b/tdesign-component/example/lib/main.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'gen_l10n/app_localizations.dart'; import 'package:tdesign_flutter/src/util/log.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart new file mode 100644 index 000000000..c72dc29bb --- /dev/null +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -0,0 +1,188 @@ +import 'package:flutter/material.dart'; +import 'package:tdesign_flutter/tdesign_flutter.dart'; + +import '../../annotation/demo.dart'; +import '../../base/example_widget.dart'; + +class TDFormPage extends StatelessWidget { + const TDFormPage({Key? key}) : super(key: key); + + final exampleTxt = '文本Text'; + + @override + Widget build(BuildContext context) { + // debugPaintBaselinesEnabled = true; + return ExamplePage( + padding: const EdgeInsets.all(8), + title: tdTitle(context), + exampleCodeGroup: 'text', + children: [ + ExampleModule(title: '使用示例', children: [ + ExampleItem(desc: '系统Text:', builder: _buildSystemText), + ExampleItem(desc: '普通TDText:', builder: _buildNormalTDText), + ExampleItem(desc: '指定常用属性:', builder: _buildGeneralProp), + ExampleItem( + desc: 'style覆盖textColor,不覆盖font:', + builder: _buildStyleCoverColor), + ExampleItem( + desc: 'style覆盖textColor和font:', + builder: _buildStyleCoverColorAndFont), + ExampleItem(desc: 'TDText.rich测试:', builder: _buildRichText), + ExampleItem(desc: '获取系统Text:', builder: _getSystemText), + ExampleItem( + desc: '中文居中:(带有英文可能不居中)', builder: _buildVerticalCenterText), + ExampleItem(desc: '自定义内部padding:', builder: _buildCustomPaddingText), + ]), + ], + test: [ + ExampleItem( + desc: '中文居中-系统字体', + builder: (context){ + return Container( + color: TDTheme.of(context).brandFocusColor, + child: Text(exampleTxt), + ); + }), + ExampleItem( + desc: '中文居中-TD字体', + builder: (context){ + return Container( + color: TDTheme.of(context).brandFocusColor, + child: TDText(exampleTxt, forceVerticalCenter: true,), + ); + }), + ], + ); + } + + @Demo(group: 'text') + Widget _buildNormalTDText(BuildContext context) { + return TDText( + exampleTxt, + ); + } + + @Demo(group: 'text') + Widget _buildSystemText(BuildContext context) { + return Text( + exampleTxt, + ); + } + + @Demo(group: 'text') + Widget _buildGeneralProp(BuildContext context) { + return TDText( + exampleTxt, + font: TDTheme.of(context).fontHeadlineLarge, + textColor: TDTheme.of(context).brandNormalColor, + backgroundColor: TDTheme.of(context).brandFocusColor, + ); + } + + @Demo(group: 'text') + Widget _buildStyleCoverColor(BuildContext context) { + return TDText( + exampleTxt, + font: TDTheme.of(context).fontBodyLarge, + textColor: TDTheme.of(context).brandNormalColor, + style: TextStyle(color: TDTheme.of(context).errorNormalColor), + ); + } + + @Demo(group: 'text') + Widget _buildStyleCoverColorAndFont(BuildContext context) { + return TDText( + exampleTxt, + font: TDTheme.of(context).fontBodyLarge, + textColor: TDTheme.of(context).brandNormalColor, + ); + } + + @Demo(group: 'text') + Widget _buildRichText(BuildContext context) { + return TDText.rich( + TextSpan(children: [ + TDTextSpan( + text: 'TDTextSpan1', + font: TDTheme.of(context).fontTitleExtraLarge, + textColor: TDTheme.of(context).warningNormalColor, + isTextThrough: true, + lineThroughColor: TDTheme.of(context).brandNormalColor, + style: TextStyle(color: TDTheme.of(context).errorNormalColor)), + TextSpan( + text: 'TextSpan2', + style: TextStyle( + fontSize: 14, color: TDTheme.of(context).brandNormalColor)), + const WidgetSpan( + child: Icon( + TDIcons.setting, + size: 24, + )), + ]), + font: TDTheme.of(context).fontBodyLarge, + textColor: TDTheme.of(context).brandNormalColor, + style: + TextStyle(color: TDTheme.of(context).errorNormalColor, fontSize: 32), + ); + } + + @Demo(group: 'text') + Widget _getSystemText(BuildContext context) { + return TDText( + exampleTxt, + backgroundColor: TDTheme.of(context).brandFocusColor, + ).getRawText(context: context); + } + + @Demo(group: 'text') + Widget _buildVerticalCenterText(BuildContext context) { + return TDText( + '中华人民共和国腾讯科技', + // font: Font(size: 100, lineHeight: 100), + forceVerticalCenter: true, + backgroundColor: TDTheme.of(context).brandFocusColor, + ); + } + + @Demo(group: 'text') + Widget _buildCustomPaddingText(BuildContext context) { + return TDTextConfiguration( + paddingConfig: CustomTextPaddingConfig(), + child: const CustomPaddingText(), + ); + } +} + +/// 自定义控件,内部的context可拿到外部TDTextConfiguration的配置信息 +class CustomPaddingText extends StatelessWidget { + const CustomPaddingText({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + TDText( + '中华人民共和国腾讯科技fgjpqy', + forceVerticalCenter: true, + backgroundColor: TDTheme.of(context).brandFocusColor, + ), + TDText( + 'English', + font: TDTheme.of(context).fontHeadlineLarge, + forceVerticalCenter: true, + backgroundColor: TDTheme.of(context).brandFocusColor, + ), + ], + ); + } +} + +/// 重写内部padding方法 +class CustomTextPaddingConfig extends TDTextPaddingConfig { + @override + EdgeInsetsGeometry getPadding(String? data, double fontSize, double height) { + var supperPadding = super.getPadding(data, fontSize, height); + return EdgeInsets.only(left: 30, top: supperPadding.vertical.toDouble()); + } +} diff --git a/tdesign-component/example/pubspec.lock b/tdesign-component/example/pubspec.lock index a208e30dd..e5af407b6 100644 --- a/tdesign-component/example/pubspec.lock +++ b/tdesign-component/example/pubspec.lock @@ -1,6 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" args: dependency: transitive description: @@ -49,6 +65,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.1" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -57,6 +97,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + dartx: + dependency: transitive + description: + name: dartx + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" + url: "https://pub.dev" + source: hosted + version: "1.2.0" fake_async: dependency: transitive description: @@ -73,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter: dependency: "direct main" description: flutter @@ -86,6 +150,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" + flutter_gen: + dependency: transitive + description: + name: flutter_gen + sha256: "7a5f9e14a151664422d37498daa0b63cda8e1068ae2c95d32d46515cb69cd227" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: "638d518897f1aefc55a24278968027591d50223a6943b6ae9aa576fe1494d99d" + url: "https://pub.dev" + source: hosted + version: "5.7.0" flutter_lints: dependency: "direct dev" description: @@ -128,6 +208,22 @@ packages: description: flutter source: sdk version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + hashcodes: + dependency: transitive + description: + name: hashcodes + sha256: "80f9410a5b3c8e110c4b7604546034749259f5d6dcca63e0d3c17c9258f1a651" + url: "https://pub.dev" + source: hosted + version: "2.0.0" http: dependency: "direct main" description: @@ -144,6 +240,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_size_getter: + dependency: transitive + description: + name: image_size_getter + sha256: f98c4246144e9b968899d2dfde69091e22a539bb64bc9b0bea51505fbb490e57 + url: "https://pub.dev" + source: hosted + version: "2.1.3" intl: dependency: "direct main" description: @@ -160,6 +264,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" lints: dependency: transitive description: @@ -200,6 +312,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -208,6 +336,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" path_provider: dependency: "direct main" description: @@ -256,6 +392,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" platform: dependency: transitive description: @@ -272,6 +416,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" sky_engine: dependency: transitive description: flutter @@ -315,7 +467,7 @@ packages: path: ".." relative: true source: path - version: "0.1.5" + version: "0.1.6" term_glyph: dependency: transitive description: @@ -332,6 +484,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" + time: + dependency: transitive + description: + name: time + sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 + url: "https://pub.dev" + source: hosted + version: "2.1.4" typed_data: dependency: transitive description: @@ -340,6 +500,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" vector_math: dependency: transitive description: @@ -348,6 +524,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" win32: dependency: transitive description: @@ -364,6 +548,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.0.0 <4.0.0" flutter: ">=3.10.0" diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart new file mode 100644 index 000000000..e69de29bb diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart new file mode 100644 index 000000000..c2f4ba5cd --- /dev/null +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +class TDForm_items extends StatefulWidget { + const TDForm_items({ + Key?key, + this.label, +}); + + /// 表格内标签 内容填充 + final String? label; + + @override + State createState() => _TDForm_itemsState(); +} + +class _TDForm_itemsState extends State { + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} \ No newline at end of file diff --git a/tdesign-component/pubspec.lock b/tdesign-component/pubspec.lock index 1a1978a1c..9ff5c7995 100644 --- a/tdesign-component/pubspec.lock +++ b/tdesign-component/pubspec.lock @@ -1,6 +1,30 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" async: dependency: transitive description: @@ -37,10 +61,50 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + url: "https://pub.dev" + source: hosted + version: "3.0.5" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + dartx: + dependency: transitive + description: + name: dartx + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.2.0" fake_async: dependency: transitive description: @@ -49,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter: dependency: "direct main" description: flutter @@ -62,6 +134,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" + flutter_gen: + dependency: "direct main" + description: + name: flutter_gen + sha256: "7a5f9e14a151664422d37498daa0b63cda8e1068ae2c95d32d46515cb69cd227" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: "638d518897f1aefc55a24278968027591d50223a6943b6ae9aa576fe1494d99d" + url: "https://pub.dev" + source: hosted + version: "5.7.0" flutter_lints: dependency: "direct dev" description: @@ -91,14 +179,62 @@ packages: description: flutter source: sdk version: "0.0.0" - js: + glob: dependency: transitive description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "2.1.2" + hashcodes: + dependency: transitive + description: + name: hashcodes + sha256: "80f9410a5b3c8e110c4b7604546034749259f5d6dcca63e0d3c17c9258f1a651" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + image_size_getter: + dependency: transitive + description: + name: image_size_getter + sha256: f98c4246144e9b968899d2dfde69091e22a539bb64bc9b0bea51505fbb490e57 + url: "https://pub.dev" + source: hosted + version: "2.1.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: @@ -111,34 +247,74 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + url: "https://pub.dev" + source: hosted + version: "1.0.6" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "2.1.0" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" sky_engine: dependency: transitive description: flutter @@ -148,26 +324,26 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -188,10 +364,42 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + time: + dependency: transitive + description: + name: time + sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.1.11+1" vector_math: dependency: transitive description: @@ -200,6 +408,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" + source: hosted + version: "14.2.1" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: - dart: ">=3.0.0-0 <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/tdesign-component/pubspec.yaml b/tdesign-component/pubspec.yaml index 276ba7b99..29392a3a9 100644 --- a/tdesign-component/pubspec.yaml +++ b/tdesign-component/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: # 滑动单元格组件 flutter_slidable: 3.1.0 + flutter_gen: ^5.7.0 # # 相册选择组件 # image_picker: 1.1.2 diff --git a/tdesign-site/package-lock.json b/tdesign-site/package-lock.json index e36d40a4c..a1004a38b 100644 --- a/tdesign-site/package-lock.json +++ b/tdesign-site/package-lock.json @@ -9,7 +9,8 @@ "version": "0.1.2", "license": "MIT", "dependencies": { - "dayjs": "^1.10.7" + "dayjs": "^1.10.7", + "tdesign-flutter": "file:" }, "devDependencies": { "@babel/core": "^7.12.10", @@ -22551,6 +22552,10 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/tdesign-flutter": { + "resolved": "", + "link": true + }, "node_modules/tdesign-icons-svg": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tdesign-icons-svg/-/tdesign-icons-svg-0.0.1.tgz", diff --git a/tdesign-site/package.json b/tdesign-site/package.json index 0d73de3f0..82da512da 100644 --- a/tdesign-site/package.json +++ b/tdesign-site/package.json @@ -121,6 +121,7 @@ ] }, "dependencies": { - "dayjs": "^1.10.7" + "dayjs": "^1.10.7", + "tdesign-flutter": "file:" } -} \ No newline at end of file +} From f71b44352ece8596b3444037f7025895140a656e Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Wed, 25 Sep 2024 10:33:37 +0800 Subject: [PATCH 02/25] =?UTF-8?q?API=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/src/components/form/td_form.dart | 80 +++++++++++++++++++ .../lib/src/components/form/td_form_item.dart | 53 ++++++++++-- 2 files changed, 126 insertions(+), 7 deletions(-) diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index e69de29bb..ef17bff11 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +class TDForm extends StatefulWidget { + const TDForm({ + Key?key, + this.colon = false, + this.contentAlign = 'left', + this.data, + this.disabled = false, + this.errorMessage, + this.labelAlign = 'right', + this.labelWidth = '81px', + this.preventSubmitDefault = true, + this.requiredMark = true, // 此处必填项有小问题 + this.resetType = 'empty', + this.rules, + this.scrollToFirstError, + this.showErrorMessage = true, + this.submitWithWarningMessage = false, + }): super(key: key); + + /// 是否在表单标签字段右侧显示冒号 + final bool? colon; + + /// 表单内容对齐方式: 左对齐、右对齐 + /// 可选项: left/right + final String? contentAlign; + + /// 表单数据 + final Object? data; + + /// 是否禁用整个表单 + final bool? disabled; + + /// 表单信息错误信息配置 + final Object? errorMessage; + + /// 表单字段标签的对齐方式: + /// 左对齐、右对齐、顶部对齐 + /// 可选项: left/right/top + final String? labelAlign; + + /// 可以整体设置 label 标签宽度,默认为 81px + final String? labelWidth; + + /// 是否阻止表单提交默认事件(表单提交默认事件会刷新页面) + /// 设置为 true 可以避免刷新 + final bool? preventSubmitDefault; + + /// 是否显示必填符号(*),默认显示 + final bool? requiredMark; + + /// 重置表单的方式,值为 empty 表示重置表单为空,值为 initial 表示重置表单数据为初始值 + /// 可选项:empty/initial + final String? resetType; + + /// 表单字段校验规则 + final Object? rules; + + /// 表单校验不通过时,是否自动滚动到第一个校验不通过的字段,平滑滚动或是瞬间直达。 + /// 值为空则表示不滚动。可选项:''/smooth/auto + final String? scrollToFirstError; + + /// 校验不通过时,是否显示错误提示信息,统一控制全部表单项 + /// 如果希望控制单个表单项,请给 FormItem 设置该属性 + final bool? showErrorMessage; + + /// 【讨论中】当校验结果只有告警信息时,是否触发 submit 提交事件 + final bool? submitWithWarningMessage; + + @override + State createState() => _TDFormState(); +} + +class _TDFormState extends State { + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} \ No newline at end of file diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index c2f4ba5cd..ccc021291 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -1,19 +1,58 @@ import 'package:flutter/material.dart'; -class TDForm_items extends StatefulWidget { - const TDForm_items({ +class TDFormIems extends StatelessWidget { + const TDFormIems({ Key?key, this.label, -}); + this.name, + this.arrow = false, + this.contentAlign = 'left', + this.help, + this.labelAlign, + this.labelWidth, + this.requiredMark, + this.rules, + this.showErrowMessage, + }): super(key: key); + /// 表单内容对齐方式: + /// 左对齐、右对齐 + /// 可选项:left/right + final String? contentAlign; + + /// 是否显示右箭头 + final bool? arrow; + + /// 表单说明内容 ???? + final help; + /// 表格内标签 内容填充 final String? label; + + /// 表单字段标签对齐方式: + /// 左对齐、右对齐、顶部对齐 + /// 默认使用 Form 的对齐方式,其优先级高于 Form.labelAlign + /// 可选项: left/right.top + final String? labelAlign; - @override - State createState() => _TDForm_itemsState(); -} + /// 可以整体调整标签宽度 + /// 优先级高于 Form.labelWidth + final String? labelWidth; + + /// 表格标识 + final String? name; + + /// 是否显示必填符号 (*) + /// 优先级高于 Form.requiredMark + final bool? requiredMark; + + /// 表单字段校验规则 ??? + final List? rules; -class _TDForm_itemsState extends State { + /// 校验不通过时,是否显示错误提示信息 + /// 优先级高于 Form.showErrowMessage + final bool? showErrowMessage; + @override Widget build(BuildContext context) { return const Placeholder(); From bb5b80b1b3d98d640b4cd3d18eb2391d04ddc72c Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Wed, 25 Sep 2024 14:38:49 +0800 Subject: [PATCH 03/25] formitem1.0 --- .../example/lib/page/td_form_page.dart | 198 ++++-------------- .../lib/src/components/form/td_form_item.dart | 55 ++++- tdesign-component/lib/tdesign_flutter.dart | 4 +- 3 files changed, 86 insertions(+), 171 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index c72dc29bb..38c1bf07b 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -18,171 +18,51 @@ class TDFormPage extends StatelessWidget { exampleCodeGroup: 'text', children: [ ExampleModule(title: '使用示例', children: [ - ExampleItem(desc: '系统Text:', builder: _buildSystemText), - ExampleItem(desc: '普通TDText:', builder: _buildNormalTDText), - ExampleItem(desc: '指定常用属性:', builder: _buildGeneralProp), - ExampleItem( - desc: 'style覆盖textColor,不覆盖font:', - builder: _buildStyleCoverColor), - ExampleItem( - desc: 'style覆盖textColor和font:', - builder: _buildStyleCoverColorAndFont), - ExampleItem(desc: 'TDText.rich测试:', builder: _buildRichText), - ExampleItem(desc: '获取系统Text:', builder: _getSystemText), - ExampleItem( - desc: '中文居中:(带有英文可能不居中)', builder: _buildVerticalCenterText), - ExampleItem(desc: '自定义内部padding:', builder: _buildCustomPaddingText), + ExampleItem(desc: '自定义内部padding:', builder: _buildUserNameItem), ]), ], - test: [ - ExampleItem( - desc: '中文居中-系统字体', - builder: (context){ - return Container( - color: TDTheme.of(context).brandFocusColor, - child: Text(exampleTxt), - ); - }), - ExampleItem( - desc: '中文居中-TD字体', - builder: (context){ - return Container( - color: TDTheme.of(context).brandFocusColor, - child: TDText(exampleTxt, forceVerticalCenter: true,), - ); - }), - ], - ); - } - - @Demo(group: 'text') - Widget _buildNormalTDText(BuildContext context) { - return TDText( - exampleTxt, - ); - } - - @Demo(group: 'text') - Widget _buildSystemText(BuildContext context) { - return Text( - exampleTxt, - ); - } - - @Demo(group: 'text') - Widget _buildGeneralProp(BuildContext context) { - return TDText( - exampleTxt, - font: TDTheme.of(context).fontHeadlineLarge, - textColor: TDTheme.of(context).brandNormalColor, - backgroundColor: TDTheme.of(context).brandFocusColor, - ); - } - - @Demo(group: 'text') - Widget _buildStyleCoverColor(BuildContext context) { - return TDText( - exampleTxt, - font: TDTheme.of(context).fontBodyLarge, - textColor: TDTheme.of(context).brandNormalColor, - style: TextStyle(color: TDTheme.of(context).errorNormalColor), - ); - } - - @Demo(group: 'text') - Widget _buildStyleCoverColorAndFont(BuildContext context) { - return TDText( - exampleTxt, - font: TDTheme.of(context).fontBodyLarge, - textColor: TDTheme.of(context).brandNormalColor, - ); - } - - @Demo(group: 'text') - Widget _buildRichText(BuildContext context) { - return TDText.rich( - TextSpan(children: [ - TDTextSpan( - text: 'TDTextSpan1', - font: TDTheme.of(context).fontTitleExtraLarge, - textColor: TDTheme.of(context).warningNormalColor, - isTextThrough: true, - lineThroughColor: TDTheme.of(context).brandNormalColor, - style: TextStyle(color: TDTheme.of(context).errorNormalColor)), - TextSpan( - text: 'TextSpan2', - style: TextStyle( - fontSize: 14, color: TDTheme.of(context).brandNormalColor)), - const WidgetSpan( - child: Icon( - TDIcons.setting, - size: 24, - )), - ]), - font: TDTheme.of(context).fontBodyLarge, - textColor: TDTheme.of(context).brandNormalColor, - style: - TextStyle(color: TDTheme.of(context).errorNormalColor, fontSize: 32), - ); - } - - @Demo(group: 'text') - Widget _getSystemText(BuildContext context) { - return TDText( - exampleTxt, - backgroundColor: TDTheme.of(context).brandFocusColor, - ).getRawText(context: context); - } - - @Demo(group: 'text') - Widget _buildVerticalCenterText(BuildContext context) { - return TDText( - '中华人民共和国腾讯科技', - // font: Font(size: 100, lineHeight: 100), - forceVerticalCenter: true, - backgroundColor: TDTheme.of(context).brandFocusColor, - ); - } - - @Demo(group: 'text') - Widget _buildCustomPaddingText(BuildContext context) { - return TDTextConfiguration( - paddingConfig: CustomTextPaddingConfig(), - child: const CustomPaddingText(), ); } } -/// 自定义控件,内部的context可拿到外部TDTextConfiguration的配置信息 -class CustomPaddingText extends StatelessWidget { - const CustomPaddingText({Key? key}) : super(key: key); - @override - Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - TDText( - '中华人民共和国腾讯科技fgjpqy', - forceVerticalCenter: true, - backgroundColor: TDTheme.of(context).brandFocusColor, - ), - TDText( - 'English', - font: TDTheme.of(context).fontHeadlineLarge, - forceVerticalCenter: true, - backgroundColor: TDTheme.of(context).brandFocusColor, - ), - ], - ); - } -} +@Demo(group: 'form') +Widget _buildUserNameItem(BuildContext buildContext) { + + return TDFormItem(); -/// 重写内部padding方法 -class CustomTextPaddingConfig extends TDTextPaddingConfig { - @override - EdgeInsetsGeometry getPadding(String? data, double fontSize, double height) { - var supperPadding = super.getPadding(data, fontSize, height); - return EdgeInsets.only(left: 30, top: supperPadding.vertical.toDouble()); - } } + +// /// 自定义控件,内部的context可拿到外部TDTextConfiguration的配置信息 +// class CustomPaddingText extends StatelessWidget { +// const CustomPaddingText({Key? key}) : super(key: key); + +// @override +// Widget build(BuildContext context) { +// return Column( +// mainAxisSize: MainAxisSize.min, +// children: [ +// TDText( +// '中华人民共和国腾讯科技fgjpqy', +// forceVerticalCenter: true, +// backgroundColor: TDTheme.of(context).brandFocusColor, +// ), +// TDText( +// 'English', +// font: TDTheme.of(context).fontHeadlineLarge, +// forceVerticalCenter: true, +// backgroundColor: TDTheme.of(context).brandFocusColor, +// ), +// ], +// ); +// } +// } + +// /// 重写内部padding方法 +// class CustomTextPaddingConfig extends TDTextPaddingConfig { +// @override +// EdgeInsetsGeometry getPadding(String? data, double fontSize, double height) { +// var supperPadding = super.getPadding(data, fontSize, height); +// return EdgeInsets.only(left: 30, top: supperPadding.vertical.toDouble()); +// } +// } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index ccc021291..d23eb5859 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -class TDFormIems extends StatelessWidget { - const TDFormIems({ - Key?key, +class TDFormItem extends StatelessWidget { + const TDFormItem({ + Key? key, this.label, this.name, this.arrow = false, @@ -13,22 +13,22 @@ class TDFormIems extends StatelessWidget { this.requiredMark, this.rules, this.showErrowMessage, - }): super(key: key); + }) : super(key: key); /// 表单内容对齐方式: /// 左对齐、右对齐 /// 可选项:left/right final String? contentAlign; - + /// 是否显示右箭头 final bool? arrow; - + /// 表单说明内容 ???? final help; - + /// 表格内标签 内容填充 final String? label; - + /// 表单字段标签对齐方式: /// 左对齐、右对齐、顶部对齐 /// 默认使用 Form 的对齐方式,其优先级高于 Form.labelAlign @@ -52,9 +52,42 @@ class TDFormIems extends StatelessWidget { /// 校验不通过时,是否显示错误提示信息 /// 优先级高于 Form.showErrowMessage final bool? showErrowMessage; - + @override Widget build(BuildContext context) { - return const Placeholder(); + return Row( + mainAxisAlignment: contentAlign == 'right' + ? MainAxisAlignment.end + : MainAxisAlignment.start, + children: [ + // 标签 + Container( + width: labelWidth != null ? double.parse(labelWidth!) : null, + alignment: labelAlign == 'right' + ? Alignment.centerRight + : labelAlign == 'top' + ? Alignment.topLeft + : Alignment.centerLeft, + child: Text( + label ?? '', + style: TextStyle( + fontWeight: + requiredMark == true ? FontWeight.bold : FontWeight.normal, + ), + ), + ), + const SizedBox(width: 8), // 标签与输入框的间距 + // 输入框 + Expanded( + child: TextFormField( + decoration: InputDecoration( + hintText: help, + suffixIcon: arrow == true ? Icon(Icons.arrow_forward) : null, + ), + // 可添加更多属性,如 validator 等 + ), + ), + ], + ); } -} \ No newline at end of file +} diff --git a/tdesign-component/lib/tdesign_flutter.dart b/tdesign-component/lib/tdesign_flutter.dart index c995c207f..a3cd067c1 100644 --- a/tdesign-component/lib/tdesign_flutter.dart +++ b/tdesign-component/lib/tdesign_flutter.dart @@ -23,6 +23,8 @@ export 'src/components/dropdown_menu/td_dropdown_item.dart'; export 'src/components/dropdown_menu/td_dropdown_menu.dart'; export 'src/components/empty/td_empty.dart'; export 'src/components/fab/td_fab.dart'; +export 'src/components/form/td_form.dart'; +export 'src/components/form/td_form_item.dart'; export 'src/components/icon/td_icons.dart'; export 'src/components/image/image_widget.dart'; export 'src/components/image/td_image.dart'; @@ -81,4 +83,4 @@ export 'src/theme/td_radius.dart'; export 'src/theme/td_shadows.dart'; export 'src/theme/td_spacers.dart'; export 'src/theme/td_theme.dart'; -export 'src/util/platform_util.dart'; +export 'src/util/platform_util.dart'; \ No newline at end of file From eb280e58b57be69a7524642098f719a9351e3db8 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 30 Sep 2024 14:13:10 +0800 Subject: [PATCH 04/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86=E5=9B=9B=E4=B8=AA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/android/build.gradle | 2 +- .../example/lib/page/td_form_page.dart | 107 +++++++++----- .../lib/src/components/form/td_form_item.dart | 139 +++++++++++++----- tdesign-component/pubspec.lock | 104 +++++-------- 4 files changed, 209 insertions(+), 143 deletions(-) diff --git a/tdesign-component/example/android/build.gradle b/tdesign-component/example/android/build.gradle index 38f569bae..53e7c1ac5 100644 --- a/tdesign-component/example/android/build.gradle +++ b/tdesign-component/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.9.0' ext { diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 38c1bf07b..6238935ee 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -7,62 +7,91 @@ import '../../base/example_widget.dart'; class TDFormPage extends StatelessWidget { const TDFormPage({Key? key}) : super(key: key); - final exampleTxt = '文本Text'; - @override Widget build(BuildContext context) { // debugPaintBaselinesEnabled = true; return ExamplePage( - padding: const EdgeInsets.all(8), title: tdTitle(context), - exampleCodeGroup: 'text', + exampleCodeGroup: 'form', + backgroundColor: const Color(0xfff6f6f6), children: [ - ExampleModule(title: '使用示例', children: [ - ExampleItem(desc: '自定义内部padding:', builder: _buildUserNameItem), + ExampleModule(title: '禁用态开关', children: [ + ExampleItem(desc: '基础开关', builder: _buildSwitchWithBase), + ]), + ExampleModule(title: 'Form', children: [ + ExampleItem(desc: '', builder: _buildUserNameItem), + ExampleItem(desc: '', builder: _buildPassWordItem), + ExampleItem(desc: '', builder: _buildhorizontalRadiosItem), ]), ], ); } } - @Demo(group: 'form') Widget _buildUserNameItem(BuildContext buildContext) { - return TDFormItem(); + return TDFormItem(label:'用户名', + name: 'name', + help:'请输入用户名'); +} + +@Demo(group: 'form') +Widget _buildPassWordItem(BuildContext buildContext) { + return TDFormItem(label:'密码', + name: 'password', + help:'请输入密码'); } -// /// 自定义控件,内部的context可拿到外部TDTextConfiguration的配置信息 -// class CustomPaddingText extends StatelessWidget { -// const CustomPaddingText({Key? key}) : super(key: key); +@Demo(group: 'form') +Widget _buildhorizontalRadiosItem(BuildContext buildContext) { -// @override -// Widget build(BuildContext context) { -// return Column( -// mainAxisSize: MainAxisSize.min, -// children: [ -// TDText( -// '中华人民共和国腾讯科技fgjpqy', -// forceVerticalCenter: true, -// backgroundColor: TDTheme.of(context).brandFocusColor, -// ), -// TDText( -// 'English', -// font: TDTheme.of(context).fontHeadlineLarge, -// forceVerticalCenter: true, -// backgroundColor: TDTheme.of(context).brandFocusColor, -// ), -// ], -// ); -// } -// } + return TDFormItem(label:'性别', + name: 'gender', + ); +} -// /// 重写内部padding方法 -// class CustomTextPaddingConfig extends TDTextPaddingConfig { -// @override -// EdgeInsetsGeometry getPadding(String? data, double fontSize, double height) { -// var supperPadding = super.getPadding(data, fontSize, height); -// return EdgeInsets.only(left: 30, top: supperPadding.vertical.toDouble()); -// } -// } +@Demo(group: 'switch') +Widget _buildSwitchWithBase(BuildContext context) { + return _buildItem( + context, + const TDSwitch(), + title: '禁用态', + ); +} + +/// 每一项的封装 +@Demo(group: 'switch') +Widget _buildItem(BuildContext context, Widget switchItem, + {String? title, String? desc}) { + final theme = TDTheme.of(context); + Widget current = Row( + children: [ + Expanded( + child: TDText( + title ?? '', + textColor: theme.fontGyColor1, + )), + TDText( + desc ?? '', + textColor: theme.grayColor6, + ), + SizedBox(child: switchItem) + ], + ); + current = Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: SizedBox( + child: Container( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: current, + ), + color: Colors.white, + ), + height: 56, + ), + ); + return Column(mainAxisSize: MainAxisSize.min, children: [current]); +} diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index d23eb5859..4613cb456 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; +import '../../../tdesign_flutter.dart'; +import '../input/td_input.dart'; -class TDFormItem extends StatelessWidget { - const TDFormItem({ - Key? key, +class TDFormItem extends StatefulWidget { + TDFormItem({ this.label, this.name, this.arrow = false, @@ -13,8 +14,12 @@ class TDFormItem extends StatelessWidget { this.requiredMark, this.rules, this.showErrowMessage, + Key? key, }) : super(key: key); + /// 表格内标签 内容填充 + final String? label; + /// 表单内容对齐方式: /// 左对齐、右对齐 /// 可选项:left/right @@ -23,11 +28,9 @@ class TDFormItem extends StatelessWidget { /// 是否显示右箭头 final bool? arrow; - /// 表单说明内容 ???? - final help; - - /// 表格内标签 内容填充 - final String? label; + /// 表单说明内容 + /// 表单的默认输入字符 + final String? help; /// 表单字段标签对齐方式: /// 左对齐、右对齐、顶部对齐 @@ -53,41 +56,99 @@ class TDFormItem extends StatelessWidget { /// 优先级高于 Form.showErrowMessage final bool? showErrowMessage; + @override + _TDFormItemState createState() => _TDFormItemState(); +} + +class _TDFormItemState extends State { + /// 实现密码右侧的可见按钮 + bool browseOn = false; + + /// 实现输入框的 controller + var controller = []; + + @override + void initState() { + for (var i = 0; i < 10; i++) { + controller.add(TextEditingController()); + } + super.initState(); + } + @override Widget build(BuildContext context) { - return Row( - mainAxisAlignment: contentAlign == 'right' - ? MainAxisAlignment.end - : MainAxisAlignment.start, - children: [ - // 标签 - Container( - width: labelWidth != null ? double.parse(labelWidth!) : null, - alignment: labelAlign == 'right' - ? Alignment.centerRight - : labelAlign == 'top' - ? Alignment.topLeft - : Alignment.centerLeft, - child: Text( - label ?? '', - style: TextStyle( - fontWeight: - requiredMark == true ? FontWeight.bold : FontWeight.normal, - ), + if (widget.name == 'name') { + return Column( + children: [ + TDInput( + leftLabel: widget.label, + required: true, + controller: controller[0], + backgroundColor: Colors.white, + hintText: widget.help, ), - ), - const SizedBox(width: 8), // 标签与输入框的间距 - // 输入框 - Expanded( - child: TextFormField( - decoration: InputDecoration( - hintText: help, - suffixIcon: arrow == true ? Icon(Icons.arrow_forward) : null, + const SizedBox( + height: 16, + ), + ], + ); + } else if (widget.name == 'password') { + return Column( + children: [ + TDInput( + type: TDInputType.normal, + controller: controller[1], + obscureText: !browseOn, + leftLabel: widget.label, + hintText: widget.help, + backgroundColor: Colors.white, + rightBtn: browseOn + ? Icon( + TDIcons.browse, + color: TDTheme.of(context).fontGyColor3, + ) + : Icon( + TDIcons.browse_off, + color: TDTheme.of(context).fontGyColor3, ), - // 可添加更多属性,如 validator 等 + onBtnTap: () { + setState(() { + browseOn = !browseOn; + }); + }, + needClear: false, + ), + const SizedBox( + height: 16, + ), + ], + ); + } else if(widget.name == 'gender'){ + return TDRadioGroup( + selectId: 'index:1', + direction: Axis.horizontal, + directionalTdRadios: const [ + TDRadio( + id: '0', + title: '男', + radioStyle: TDRadioStyle.circle, + showDivider: false, + ), + TDRadio( + id: '1', + title: '女', + radioStyle: TDRadioStyle.circle, + showDivider: false, + ), + TDRadio( + id: '2', + title: '保密', + radioStyle: TDRadioStyle.circle, + showDivider: false, ), - ), - ], - ); + ], + ); + } + return Column(); } } diff --git a/tdesign-component/pubspec.lock b/tdesign-component/pubspec.lock index 9ff5c7995..134be1f97 100644 --- a/tdesign-component/pubspec.lock +++ b/tdesign-component/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "64.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.2.0" args: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.1" color: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: crypto - sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.3" dart_style: dependency: transitive description: @@ -203,38 +203,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" - url: "https://pub.dev" - source: hosted - version: "10.0.4" - leak_tracker_flutter_testing: + js: dependency: transitive description: - name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "3.0.3" - leak_tracker_testing: + version: "0.6.7" + json_annotation: dependency: transitive description: - name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "4.9.0" lints: dependency: transitive description: @@ -247,34 +231,34 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.15" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.2.0" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.9.1" mime: dependency: transitive description: name: mime - sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "1.0.4" package_config: dependency: transitive description: @@ -287,10 +271,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_parsing: dependency: transitive description: @@ -303,10 +287,10 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "5.4.0" pub_semver: dependency: transitive description: @@ -324,26 +308,26 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -364,10 +348,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.5.1" time: dependency: transitive description: @@ -408,14 +392,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" - url: "https://pub.dev" - source: hosted - version: "14.2.1" watcher: dependency: transitive description: @@ -428,10 +404,10 @@ packages: dependency: transitive description: name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.3.0" yaml: dependency: transitive description: @@ -441,5 +417,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.7.0" From 4f870d6d150931353318c6756f17de84e57601f0 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 30 Sep 2024 19:37:10 +0800 Subject: [PATCH 05/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86=E8=AE=A1=E6=95=B0=E5=99=A8=E5=92=8C=E5=8D=8A=E4=B8=AA?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E9=80=89=E6=8B=A9=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 168 +++++++++++------- .../lib/src/components/form/td_form_item.dart | 105 +++++++++-- 2 files changed, 197 insertions(+), 76 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 6238935ee..f55f48b98 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -4,14 +4,30 @@ import 'package:tdesign_flutter/tdesign_flutter.dart'; import '../../annotation/demo.dart'; import '../../base/example_widget.dart'; -class TDFormPage extends StatelessWidget { +class TDFormPage extends StatefulWidget { const TDFormPage({Key? key}) : super(key: key); + @override + _TDFormPageState createState() => _TDFormPageState(); +} + +class _TDFormPageState extends State { + + var controller = []; + String selected_1 = ''; + + @override + void initState() { + for (var i = 0; i < 28; i++) { + controller.add(TextEditingController()); + } + super.initState(); + } + @override Widget build(BuildContext context) { - // debugPaintBaselinesEnabled = true; return ExamplePage( - title: tdTitle(context), + title: tdTitle(), exampleCodeGroup: 'form', backgroundColor: const Color(0xfff6f6f6), children: [ @@ -22,76 +38,104 @@ class TDFormPage extends StatelessWidget { ExampleItem(desc: '', builder: _buildUserNameItem), ExampleItem(desc: '', builder: _buildPassWordItem), ExampleItem(desc: '', builder: _buildhorizontalRadiosItem), + ExampleItem(desc: '', builder: _buildDateItem), + ExampleItem(desc: '', builder: _buildStepperItem), ]), ], ); } -} -@Demo(group: 'form') -Widget _buildUserNameItem(BuildContext buildContext) { - - return TDFormItem(label:'用户名', - name: 'name', - help:'请输入用户名'); -} - -@Demo(group: 'form') -Widget _buildPassWordItem(BuildContext buildContext) { + @Demo(group: 'form') + Widget _buildUserNameItem(BuildContext buildContext) { + return TDFormItem( + label: '用户名', + name: 'name', + help: '请输入用户名', + controller: controller[0], + ); + } - return TDFormItem(label:'密码', + @Demo(group: 'form') + Widget _buildPassWordItem(BuildContext buildContext) { + return TDFormItem( + label: '密码', name: 'password', - help:'请输入密码'); -} - -@Demo(group: 'form') -Widget _buildhorizontalRadiosItem(BuildContext buildContext) { + help: '请输入密码', + controller: controller[1], + ); + } - return TDFormItem(label:'性别', + @Demo(group: 'form') + Widget _buildhorizontalRadiosItem(BuildContext buildContext) { + return TDFormItem( + label: '性别', name: 'gender', - ); -} + /// 扩展一下数量和选项内容 + ); + } -@Demo(group: 'switch') -Widget _buildSwitchWithBase(BuildContext context) { - return _buildItem( - context, - const TDSwitch(), - title: '禁用态', - ); -} + @Demo(group: 'form') + Widget _buildDateItem(BuildContext buildContext){ + return TDFormItem( + label: '生日', + name: 'date', + /// 引入需要的日期数据 + select: selected_1, + ); + } -/// 每一项的封装 -@Demo(group: 'switch') -Widget _buildItem(BuildContext context, Widget switchItem, - {String? title, String? desc}) { - final theme = TDTheme.of(context); - Widget current = Row( - children: [ - Expanded( - child: TDText( - title ?? '', - textColor: theme.fontGyColor1, - )), - TDText( - desc ?? '', - textColor: theme.grayColor6, - ), - SizedBox(child: switchItem) - ], - ); - current = Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: SizedBox( - child: Container( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: current, + @Demo(group: 'form') + Widget _buildStepperItem(BuildContext buildContext){ + return TDFormItem( + label: '年限', + name: 'age', + /// 为 TDStepper 预留其他设置 + ); + } + + @Demo(group: 'switch') + Widget _buildSwitchWithBase(BuildContext context) { + return _buildItem( + context, + const TDSwitch(), + title: '禁用态', + ); + } + + /// 每一项的封装 + @Demo(group: 'switch') + Widget _buildItem(BuildContext context, Widget switchItem, + {String? title, String? desc}) { + final theme = TDTheme.of(context); + Widget current = Row( + children: [ + Expanded( + child: TDText( + title ?? '', + textColor: theme.fontGyColor1, + )), + TDText( + desc ?? '', + textColor: theme.grayColor6, + ), + SizedBox(child: switchItem) + ], + ); + current = Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: SizedBox( + child: Container( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: current, + ), + color: Colors.white, ), - color: Colors.white, + height: 56, ), - height: 56, - ), - ); - return Column(mainAxisSize: MainAxisSize.min, children: [current]); + ); + return Column(mainAxisSize: MainAxisSize.min, children: [current]); + } } + + diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 4613cb456..a9e94c9c2 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -4,6 +4,8 @@ import '../input/td_input.dart'; class TDFormItem extends StatefulWidget { TDFormItem({ + this.controller, + this.select = '', this.label, this.name, this.arrow = false, @@ -45,11 +47,17 @@ class TDFormItem extends StatefulWidget { /// 表格标识 final String? name; + /// 表格的 controller + var controller; + + /// 日期选择需要展示的内容 + String select; + /// 是否显示必填符号 (*) /// 优先级高于 Form.requiredMark final bool? requiredMark; - /// 表单字段校验规则 ??? + /// 表单字段校验规则 final List? rules; /// 校验不通过时,是否显示错误提示信息 @@ -60,21 +68,49 @@ class TDFormItem extends StatefulWidget { _TDFormItemState createState() => _TDFormItemState(); } +Widget buildSelectRow(BuildContext context, String output, String title) { + return Container( + color: TDTheme.of(context).whiteColor1, + height: 56, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + child: TDText(title, font: TDTheme.of(context).fontBodyLarge,), + ), + Padding( + padding: const EdgeInsets.only(right: 16), + child: Row( + children: [ + TDText( + output, + font: TDTheme.of(context).fontBodyLarge, + textColor: TDTheme.of(context).fontGyColor3.withOpacity(0.4),), + Padding( + padding: const EdgeInsets.only(left: 2), + child: Icon( + TDIcons.chevron_right, + color: TDTheme.of(context).fontGyColor3.withOpacity(0.4),), + ), + ], + ), + ), + ], + ), + const TDDivider(margin: EdgeInsets.only(left: 16, ),) + ], + ), + ); +} + class _TDFormItemState extends State { /// 实现密码右侧的可见按钮 bool browseOn = false; - /// 实现输入框的 controller - var controller = []; - - @override - void initState() { - for (var i = 0; i < 10; i++) { - controller.add(TextEditingController()); - } - super.initState(); - } - @override Widget build(BuildContext context) { if (widget.name == 'name') { @@ -83,7 +119,7 @@ class _TDFormItemState extends State { TDInput( leftLabel: widget.label, required: true, - controller: controller[0], + controller: widget.controller, backgroundColor: Colors.white, hintText: widget.help, ), @@ -97,7 +133,7 @@ class _TDFormItemState extends State { children: [ TDInput( type: TDInputType.normal, - controller: controller[1], + controller: widget.controller, obscureText: !browseOn, leftLabel: widget.label, hintText: widget.help, @@ -148,7 +184,48 @@ class _TDFormItemState extends State { ), ], ); + } else if(widget.name == 'date'){ + return GestureDetector( + onTap: (){ + TDPicker.showDatePicker(context, title: '选择时间', + onConfirm: (selected) { + setState(() { + widget.select = '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + }); + Navigator.of(context).pop(); + }, + dateStart: [1999, 01, 01], + dateEnd: [2023, 12, 31], + initialDate: [2012, 1, 1]); + }, + child: buildSelectRow(context, widget.select, '选择时间'), + ); + }else if(widget.name == 'age'){ + final theme = TDTheme.of(context); + + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, // 左右分布 + children: [ + TDText( + widget.label, // 左侧的文本 + style: TextStyle(fontSize: 16), // 可根据需要设置样式 + ), + TDStepper( + theme: TDStepperTheme.filled, // 右侧的步进器 + ), + ], + ), + ), + ); } + + return Column(); } } From 8881f8123fe546e32883b82c1346d6e3aecc93b7 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 1 Oct 2024 09:43:18 +0800 Subject: [PATCH 06/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86=E5=9E=82=E7=9B=B4=E5=A4=9A=E7=BA=A7=E8=81=94=E5=90=88?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 81 ++++++++++++++++++ .../lib/src/components/form/td_form_item.dart | 85 ++++++++++++++++++- 2 files changed, 164 insertions(+), 2 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index f55f48b98..71b3b3431 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -15,6 +15,76 @@ class _TDFormPageState extends State { var controller = []; String selected_1 = ''; + List _data = [ + { + "label": '北京市', + "value": '110000', + "children": [ + { + "value": '110100', + "label": '北京市', + "children": [ + {"value": '110101', "label": '东城区'}, + {"value": '1101022', "label": '东区'}, + {"value": '110102', "label": '西城区'}, + {"value": '110105', "label": '朝阳区'}, + {"value": '110106', "label": '丰台区'}, + {"value": '110107', "label": '石景山区'}, + {"value": '110108', "label": '海淀区'}, + {"value": '110109', "label": '门头沟区'}, + ], + }, + ], + }, + { + "label": '天津市', + "value": '120000', + "children": [ + { + "value": '120100', + "label": '天津市', + "children": [ + { + "value": '120101', + "label": '和平区', + }, + { + "value": '120102', + "label": '河东区', + }, + { + "value": '120103', + "label": '河西区', + }, + { + "value": '120104', + "label": '南开区', + }, + { + "value": '120105', + "label": '河北区', + }, + { + "value": '120106', + "label": '红桥区', + }, + { + "value": '120110', + "label": '东丽区', + }, + { + "value": '120111', + "label": '西青区', + }, + { + "value": '120112', + "label": '津南区', + }, + ], + }, + ], + }, + ]; @override void initState() { @@ -39,6 +109,7 @@ class _TDFormPageState extends State { ExampleItem(desc: '', builder: _buildPassWordItem), ExampleItem(desc: '', builder: _buildhorizontalRadiosItem), ExampleItem(desc: '', builder: _buildDateItem), + ExampleItem(desc: '', builder: _buildCascaderItem), ExampleItem(desc: '', builder: _buildStepperItem), ]), ], @@ -84,6 +155,16 @@ class _TDFormPageState extends State { ); } + @Demo(group: 'form') + Widget _buildCascaderItem(BuildContext buildContext){ + return TDFormItem( + label: '籍贯', + name: 'local', + /// 引入需要的地点数据 + localData: _data, + ); + } + @Demo(group: 'form') Widget _buildStepperItem(BuildContext buildContext){ return TDFormItem( diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index a9e94c9c2..c726c636b 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -4,8 +4,10 @@ import '../input/td_input.dart'; class TDFormItem extends StatefulWidget { TDFormItem({ + /// 需要从 page 外部传入的参数 this.controller, this.select = '', + List? localData, this.label, this.name, this.arrow = false, @@ -17,7 +19,8 @@ class TDFormItem extends StatefulWidget { this.rules, this.showErrowMessage, Key? key, - }) : super(key: key); + }) : localData = localData ?? const [], + super(key: key); /// 表格内标签 内容填充 final String? label; @@ -53,6 +56,9 @@ class TDFormItem extends StatefulWidget { /// 日期选择需要展示的内容 String select; + /// 组相联选择器需要的数据 + final List localData; + /// 是否显示必填符号 (*) /// 优先级高于 Form.requiredMark final bool? requiredMark; @@ -111,6 +117,10 @@ class _TDFormItemState extends State { /// 实现密码右侧的可见按钮 bool browseOn = false; + /// 垂直联级选择器 + String? _initData; + String _selected_1 = ''; + @override Widget build(BuildContext context) { if (widget.name == 'name') { @@ -223,9 +233,80 @@ class _TDFormItemState extends State { ), ), ); + }else if(widget.name == 'local'){ + return GestureDetector( + onTap: () { + TDCascader.showMultiCascader(context, title: '选择地址', data: widget.localData, initialData: _initData, theme: 'step', + onChange: (List selectData) { + setState(() { + List result = []; + int len = selectData.length; + _initData = selectData[len - 1].value!; + selectData.forEach((element) { + result.add(element.label); + }); + _selected_1 = result.join('/'); + }); + }, onClose: () { + Navigator.of(context).pop(); + }); + }, + child: _buildSelectRow(context, _selected_1, '选择地区'), + ); } + return Column(); + } - return Column(); + Widget _buildSelectRow(BuildContext context, String output, String title) { + return Container( + color: TDTheme.of(context).whiteColor1, + height: 56, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + child: TDText( + title, + font: TDTheme.of(context).fontBodyLarge, + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 16, left: 16), + child: Row( + children: [ + Expanded( + child: TDText( + output, + font: TDTheme.of(context).fontBodyLarge, + textColor: TDTheme.of(context).fontGyColor3.withOpacity(0.4), + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + Padding( + padding: const EdgeInsets.only(left: 2), + child: Icon( + TDIcons.chevron_right, + color: TDTheme.of(context).fontGyColor3.withOpacity(0.4), + ), + ), + ], + ), + )), + ], + ), + const TDDivider( + margin: EdgeInsets.only( + left: 16, + ), + ) + ], + ), + ); } } From f5101bc88f72687af71c35eee21bd61f32e4d40c Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Thu, 3 Oct 2024 19:29:50 +0800 Subject: [PATCH 07/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86Form=E7=9A=84=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_cell_page.dart | 46 +++- .../example/lib/page/td_form_page.dart | 204 ++++++++++------ .../lib/src/components/button/td_button.dart | 45 ++-- .../src/components/cell/td_cell_group.dart | 29 ++- .../lib/src/components/form/td_form.dart | 24 +- .../lib/src/components/form/td_form_item.dart | 220 +++++++++++------- 6 files changed, 376 insertions(+), 192 deletions(-) diff --git a/tdesign-component/example/lib/page/td_cell_page.dart b/tdesign-component/example/lib/page/td_cell_page.dart index 9ec21100d..0ae83a49d 100644 --- a/tdesign-component/example/lib/page/td_cell_page.dart +++ b/tdesign-component/example/lib/page/td_cell_page.dart @@ -72,8 +72,12 @@ Widget _buildSimple(BuildContext context) { cells: [ TDCell(arrow: true, title: '单行标题'), TDCell(arrow: true, title: '单行标题', required: true), - TDCell(arrow: true, title: '单行标题', noteWidget: TDBadge(TDBadgeType.message, count: '8')), - TDCell(arrow: false, title: '单行标题', rightIconWidget: TDSwitch(isOn: true)), + TDCell( + arrow: true, + title: '单行标题', + noteWidget: TDBadge(TDBadgeType.message, count: '8')), + TDCell( + arrow: false, title: '单行标题', rightIconWidget: TDSwitch(isOn: true)), TDCell(arrow: true, title: '单行标题', note: '辅助信息'), TDCell(arrow: true, title: '单行标题', leftIcon: TDIcons.lock_on), TDCell(arrow: false, title: '单行标题'), @@ -86,14 +90,36 @@ Widget _buildDesSimple(BuildContext context) { return const TDCellGroup( cells: [ TDCell(arrow: true, title: '单行标题', description: '一段很长很长的内容文字'), - TDCell(arrow: true, title: '单行标题', description: '一段很长很长的内容文字', required: true), TDCell( - arrow: true, title: '单行标题', description: '一段很长很长的内容文字', noteWidget: TDBadge(TDBadgeType.message, count: '8')), - TDCell(arrow: false, title: '单行标题', description: '一段很长很长的内容文字', rightIconWidget: TDSwitch(isOn: true)), - TDCell(arrow: true, title: '单行标题', description: '一段很长很长的内容文字', note: '辅助信息'), - TDCell(arrow: true, title: '单行标题', description: '一段很长很长的内容文字一段很长很长的内容文字一段很长很长的内', leftIcon: TDIcons.lock_on), - TDCell(arrow: false, title: '单行标题', description: '一段很长很长的内容文字一段很长很长的内容文字一段很长很长的内'), - TDCell(arrow: false, title: '多行高度不定,长文本自动换行,该选项的描述是一段很长的内容', description: '一段很长很长的内容文字一段很长很长的内容文字一段很长很长的内'), + arrow: true, + title: '单行标题', + description: '一段很长很长的内容文字', + required: true), + TDCell( + arrow: true, + title: '单行标题', + description: '一段很长很长的内容文字', + noteWidget: TDBadge(TDBadgeType.message, count: '8')), + TDCell( + arrow: false, + title: '单行标题', + description: '一段很长很长的内容文字', + rightIconWidget: TDSwitch(isOn: true)), + TDCell( + arrow: true, title: '单行标题', description: '一段很长很长的内容文字', note: '辅助信息'), + TDCell( + arrow: true, + title: '单行标题', + description: '一段很长很长的内容文字一段很长很长的内容文字一段很长很长的内', + leftIcon: TDIcons.lock_on), + TDCell( + arrow: false, + title: '单行标题', + description: '一段很长很长的内容文字一段很长很长的内容文字一段很长很长的内'), + TDCell( + arrow: false, + title: '多行高度不定,长文本自动换行,该选项的描述是一段很长的内容', + description: '一段很长很长的内容文字一段很长很长的内容文字一段很长很长的内'), TDCell( arrow: true, title: '多行带头像', @@ -150,4 +176,4 @@ Widget _buildCard(BuildContext context) { // TDCell(title: 'item', leftIcon: TDIcons.app), // ], // ); -// } \ No newline at end of file +// } diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 71b3b3431..50ef3cab6 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -12,9 +12,16 @@ class TDFormPage extends StatefulWidget { } class _TDFormPageState extends State { - var controller = []; String selected_1 = ''; + + Color verticalTextColor = Colors.black; + Color horizontalTextColor = Colors.red; + Color verticalButtonColor = Colors.blueGrey; + Color horizontalButtonColor = Colors.blue; + + Map _radios = {"0": "男", "1": "女", "2": "保密"}; + List _data = [ { "label": '北京市', @@ -97,81 +104,138 @@ class _TDFormPageState extends State { @override Widget build(BuildContext context) { return ExamplePage( - title: tdTitle(), - exampleCodeGroup: 'form', - backgroundColor: const Color(0xfff6f6f6), - children: [ - ExampleModule(title: '禁用态开关', children: [ - ExampleItem(desc: '基础开关', builder: _buildSwitchWithBase), - ]), - ExampleModule(title: 'Form', children: [ - ExampleItem(desc: '', builder: _buildUserNameItem), - ExampleItem(desc: '', builder: _buildPassWordItem), - ExampleItem(desc: '', builder: _buildhorizontalRadiosItem), - ExampleItem(desc: '', builder: _buildDateItem), - ExampleItem(desc: '', builder: _buildCascaderItem), - ExampleItem(desc: '', builder: _buildStepperItem), - ]), - ], - ); + title: tdTitle(), + exampleCodeGroup: 'form', + desc: '基础表单', + backgroundColor: const Color(0xfff6f6f6), + children: [ + ExampleModule(title: '基础类型', children: [ + ExampleItem(desc: '基础表单', builder: _buildArrangementSwitch), + ExampleItem(desc: '', builder: _buildSwitchWithBase), + ExampleItem(builder: (BuildContext context) { + return CodeWrapper(builder: _buildForm); + }) + ]), + ]); } @Demo(group: 'form') - Widget _buildUserNameItem(BuildContext buildContext) { - return TDFormItem( - label: '用户名', - name: 'name', - help: '请输入用户名', - controller: controller[0], - ); - } + Widget _buildForm(BuildContext context) { + return TDForm(items: [ + TDFormItem( + label: '用户名', + name: 'name', + help: '请输入用户名', + controller: controller[0], + ), + TDFormItem( + label: '密码', + name: 'password', + help: '请输入密码', + controller: controller[1], + ), + TDFormItem( + label: '性别', + name: 'radios', - @Demo(group: 'form') - Widget _buildPassWordItem(BuildContext buildContext) { - return TDFormItem( - label: '密码', - name: 'password', - help: '请输入密码', - controller: controller[1], - ); - } + /// 扩展一下数量和选项内容 + radios: _radios, + ), + TDFormItem( + label: '生日', + name: 'date', - @Demo(group: 'form') - Widget _buildhorizontalRadiosItem(BuildContext buildContext) { - return TDFormItem( - label: '性别', - name: 'gender', - /// 扩展一下数量和选项内容 - ); - } + /// 引入需要的日期数据 + select: selected_1, + ), + TDFormItem( + label: '籍贯', + name: 'local', - @Demo(group: 'form') - Widget _buildDateItem(BuildContext buildContext){ - return TDFormItem( - label: '生日', - name: 'date', - /// 引入需要的日期数据 - select: selected_1, - ); - } + /// 引入需要的地点数据 + localData: _data, + ), + TDFormItem( + label: '年限', + name: 'age', - @Demo(group: 'form') - Widget _buildCascaderItem(BuildContext buildContext){ - return TDFormItem( - label: '籍贯', - name: 'local', - /// 引入需要的地点数据 - localData: _data, - ); + /// 为 TDStepper 预留其他设置 + ), + TDFormItem( + label: '个人简介', + name: 'textarea', + help: '请输入个人简介', + controller: controller[2], + + /// 为 TDTextarea 长文本其他参数做预留 API + maxLength: 500, + indicator: true, + ) + ]); } + /// 横 竖 排版模式切换 @Demo(group: 'form') - Widget _buildStepperItem(BuildContext buildContext){ - return TDFormItem( - label: '年限', - name: 'age', - /// 为 TDStepper 预留其他设置 - ); + Widget _buildArrangementSwitch(BuildContext buildContext) { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Expanded( + child: TDButton( + text: '水平排布', + shape: TDButtonShape.round, + style: + TDButtonStyle(backgroundColor: horizontalButtonColor), + textStyle: TextStyle( + fontWeight: FontWeight.w700, + color: horizontalTextColor, + ), + onTap: () { + setState(() { + print("____1"); + final currentVerticalColor = verticalButtonColor; + verticalButtonColor = horizontalButtonColor; + horizontalButtonColor = currentVerticalColor; + + final currentTextColor = verticalTextColor; + verticalTextColor = horizontalTextColor; + horizontalTextColor = currentTextColor; + }); + }, + ), + ), + SizedBox(width: 8), + Expanded( + child: TDButton( + text: '竖直排布', + shape: TDButtonShape.round, + style: TDButtonStyle(backgroundColor: verticalButtonColor), + textStyle: TextStyle( + fontWeight: FontWeight.w700, + color: verticalTextColor, + ), + onTap: () { + setState(() { + print("____2"); + final currentVerticalColor = verticalButtonColor; + verticalButtonColor = horizontalButtonColor; + horizontalButtonColor = currentVerticalColor; + + final currentTextColor = verticalTextColor; + verticalTextColor = horizontalTextColor; + horizontalTextColor = currentTextColor; + }); + }, + ), + ), + ], + ))); } @Demo(group: 'switch') @@ -192,9 +256,9 @@ class _TDFormPageState extends State { children: [ Expanded( child: TDText( - title ?? '', - textColor: theme.fontGyColor1, - )), + title ?? '', + textColor: theme.fontGyColor1, + )), TDText( desc ?? '', textColor: theme.grayColor6, @@ -218,5 +282,3 @@ class _TDFormPageState extends State { return Column(mainAxisSize: MainAxisSize.min, children: [current]); } } - - diff --git a/tdesign-component/lib/src/components/button/td_button.dart b/tdesign-component/lib/src/components/button/td_button.dart index db4070f6f..c7b1c3b67 100644 --- a/tdesign-component/lib/src/components/button/td_button.dart +++ b/tdesign-component/lib/src/components/button/td_button.dart @@ -121,14 +121,17 @@ class _TDButtonState extends State { double? _iconSize; _updateParams() async { - _buttonStatus = widget.disabled ? TDButtonStatus.disable : TDButtonStatus.defaultState; + _buttonStatus = + widget.disabled ? TDButtonStatus.disable : TDButtonStatus.defaultState; _innerDefaultStyle = widget.style; _innerActiveStyle = widget.activeStyle; _innerDisableStyle = widget.disableStyle; _width = _getWidth(); _height = _getHeight(); _margin = _getMargin(); - _alignment = widget.shape == TDButtonShape.filled || widget.isBlock ? Alignment.center : null; + _alignment = widget.shape == TDButtonShape.filled || widget.isBlock + ? Alignment.center + : null; if (widget.text != null) { _textStyle = widget.disabled ? widget.disableTextStyle : widget.textStyle; } @@ -187,7 +190,7 @@ class _TDButtonState extends State { }, onTapUp: (TapUpDetails details) { Future.delayed(const Duration(milliseconds: 100), () { - if (mounted&&!widget.disabled) { + if (mounted && !widget.disabled) { setState(() { _buttonStatus = TDButtonStatus.defaultState; }); @@ -277,13 +280,17 @@ class _TDButtonState extends State { Font _getTextFont() { switch (widget.size) { case TDButtonSize.large: - return TDTheme.of(context).fontMarkLarge ?? Font(size: 16, lineHeight: 24); + return TDTheme.of(context).fontMarkLarge ?? + Font(size: 16, lineHeight: 24); case TDButtonSize.medium: - return TDTheme.of(context).fontMarkLarge ?? Font(size: 16, lineHeight: 24); + return TDTheme.of(context).fontMarkLarge ?? + Font(size: 16, lineHeight: 24); case TDButtonSize.small: - return TDTheme.of(context).fontMarkMedium ?? Font(size: 14, lineHeight: 22); + return TDTheme.of(context).fontMarkMedium ?? + Font(size: 14, lineHeight: 22); case TDButtonSize.extraSmall: - return TDTheme.of(context).fontMarkMedium ?? Font(size: 14, lineHeight: 22); + return TDTheme.of(context).fontMarkMedium ?? + Font(size: 14, lineHeight: 22); } } @@ -291,7 +298,9 @@ class _TDButtonState extends State { if (widget.width != null) { return widget.width; } - if (!widget.isBlock && (widget.shape == TDButtonShape.square || widget.shape == TDButtonShape.circle)) { + if (!widget.isBlock && + (widget.shape == TDButtonShape.square || + widget.shape == TDButtonShape.circle)) { switch (widget.size) { case TDButtonSize.large: return 48; @@ -346,7 +355,8 @@ class _TDButtonState extends State { if (widget.padding != null) { return widget.padding; } - var equalSide = widget.shape == TDButtonShape.square || widget.shape == TDButtonShape.circle; + var equalSide = widget.shape == TDButtonShape.square || + widget.shape == TDButtonShape.circle; double horizontalPadding; double verticalPadding; @@ -379,7 +389,10 @@ class _TDButtonState extends State { } } return EdgeInsets.only( - left: horizontalPadding, right: horizontalPadding, bottom: verticalPadding, top: verticalPadding); + left: horizontalPadding, + right: horizontalPadding, + bottom: verticalPadding, + top: verticalPadding); } @override @@ -391,13 +404,17 @@ class _TDButtonState extends State { TDButtonStyle _generateInnerStyle() { switch (widget.type) { case TDButtonType.fill: - return TDButtonStyle.generateFillStyleByTheme(context, widget.theme, _buttonStatus); + return TDButtonStyle.generateFillStyleByTheme( + context, widget.theme, _buttonStatus); case TDButtonType.outline: - return TDButtonStyle.generateOutlineStyleByTheme(context, widget.theme, _buttonStatus); + return TDButtonStyle.generateOutlineStyleByTheme( + context, widget.theme, _buttonStatus); case TDButtonType.text: - return TDButtonStyle.generateTextStyleByTheme(context, widget.theme, _buttonStatus); + return TDButtonStyle.generateTextStyleByTheme( + context, widget.theme, _buttonStatus); case TDButtonType.ghost: - return TDButtonStyle.generateGhostStyleByTheme(context, widget.theme, _buttonStatus); + return TDButtonStyle.generateGhostStyleByTheme( + context, widget.theme, _buttonStatus); } } diff --git a/tdesign-component/lib/src/components/cell/td_cell_group.dart b/tdesign-component/lib/src/components/cell/td_cell_group.dart index 98454285e..758267658 100644 --- a/tdesign-component/lib/src/components/cell/td_cell_group.dart +++ b/tdesign-component/lib/src/components/cell/td_cell_group.dart @@ -3,7 +3,8 @@ import 'package:flutter/material.dart'; import '../../../tdesign_flutter.dart'; import 'td_cell_inherited.dart'; -typedef CellBuilder = Widget Function(BuildContext context, TDCell cell, int index); +typedef CellBuilder = Widget Function( + BuildContext context, TDCell cell, int index); enum TDCellGroupTheme { defaultTheme, cardTheme } @@ -76,25 +77,32 @@ class _TDCellGroupState extends State { top: TDTheme.of(context).spacer24, bottom: TDTheme.of(context).spacer8, ), - child: widget.titleWidget ?? TDText(widget.title!, style: style.groupTitleStyle), + child: widget.titleWidget ?? + TDText(widget.title!, style: style.groupTitleStyle), ), Flexible( child: Container( padding: widget.theme == TDCellGroupTheme.cardTheme ? EdgeInsets.only(left: spacer16, right: spacer16) : EdgeInsets.zero, - decoration: BoxDecoration(border: _getBordered(style), borderRadius: radius), + decoration: BoxDecoration( + border: _getBordered(style), borderRadius: radius), child: ClipRRect( borderRadius: radius, child: ListView.separated( padding: EdgeInsets.zero, shrinkWrap: widget.scrollable == false, // 设置为true以避免无限制地增长 - physics: widget.scrollable == false ? const NeverScrollableScrollPhysics() : null, // 禁用ListView的滚动 + physics: widget.scrollable == false + ? const NeverScrollableScrollPhysics() + : null, // 禁用ListView的滚动 itemCount: itemCount, itemBuilder: (context, index) { final item = widget.cells[index]; - final cell = widget.builder == null ? item : widget.builder!(context, item, index); - if (itemCount - 1 == index && (widget.isShowLastBordered ?? false)) { + final cell = widget.builder == null + ? item + : widget.builder!(context, item, index); + if (itemCount - 1 == index && + (widget.isShowLastBordered ?? false)) { return Column(children: [cell, _borderWidget(style)]); } return cell; @@ -135,9 +143,14 @@ class _TDCellGroupState extends State { Widget _borderWidget(TDCellStyle style) { return Row( children: [ - Container(height: 0.5, width: TDTheme.of(context).spacer16, color: style.backgroundColor), + Container( + height: 0.5, + width: TDTheme.of(context).spacer16, + color: style.backgroundColor), Expanded( - child: Container(height: 0.5, color: style.borderedColor ?? TDTheme.of(context).grayColor3), + child: Container( + height: 0.5, + color: style.borderedColor ?? TDTheme.of(context).grayColor3), ), ], ); diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index ef17bff11..6fdd5ffd1 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import '../../../tdesign_flutter.dart'; class TDForm extends StatefulWidget { const TDForm({ - Key?key, + Key? key, + required this.items, this.colon = false, this.contentAlign = 'left', this.data, @@ -17,7 +19,10 @@ class TDForm extends StatefulWidget { this.scrollToFirstError, this.showErrorMessage = true, this.submitWithWarningMessage = false, - }): super(key: key); + }) : super(key: key); + + /// 表单内容 items + final List items; /// 是否在表单标签字段右侧显示冒号 final bool? colon; @@ -75,6 +80,17 @@ class TDForm extends StatefulWidget { class _TDFormState extends State { @override Widget build(BuildContext context) { - return const Placeholder(); + return Container( + child: ListView.separated( + shrinkWrap: true, + itemCount: widget.items.length, + itemBuilder: (context, index) { + return widget.items[index]; + }, + separatorBuilder: (context, index) { + return SizedBox(height: 1); + }, + ), + ); } -} \ No newline at end of file +} diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index c726c636b..03d3f95b3 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import '../../../tdesign_flutter.dart'; -import '../input/td_input.dart'; class TDFormItem extends StatefulWidget { TDFormItem({ @@ -8,6 +7,7 @@ class TDFormItem extends StatefulWidget { this.controller, this.select = '', List? localData, + Map? radios, this.label, this.name, this.arrow = false, @@ -18,8 +18,11 @@ class TDFormItem extends StatefulWidget { this.requiredMark, this.rules, this.showErrowMessage, + this.maxLength, + this.indicator, Key? key, }) : localData = localData ?? const [], + radios = radios ?? const {}, super(key: key); /// 表格内标签 内容填充 @@ -59,6 +62,9 @@ class TDFormItem extends StatefulWidget { /// 组相联选择器需要的数据 final List localData; + /// 单选框数据 + final Map radios; + /// 是否显示必填符号 (*) /// 优先级高于 Form.requiredMark final bool? requiredMark; @@ -70,6 +76,10 @@ class TDFormItem extends StatefulWidget { /// 优先级高于 Form.showErrowMessage final bool? showErrowMessage; + /// TDTextarea 预留API + final int? maxLength; + final bool? indicator; + @override _TDFormItemState createState() => _TDFormItemState(); } @@ -86,7 +96,10 @@ Widget buildSelectRow(BuildContext context, String output, String title) { children: [ Padding( padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), - child: TDText(title, font: TDTheme.of(context).fontBodyLarge,), + child: TDText( + title, + font: TDTheme.of(context).fontBodyLarge, + ), ), Padding( padding: const EdgeInsets.only(right: 16), @@ -95,19 +108,26 @@ Widget buildSelectRow(BuildContext context, String output, String title) { TDText( output, font: TDTheme.of(context).fontBodyLarge, - textColor: TDTheme.of(context).fontGyColor3.withOpacity(0.4),), + textColor: + TDTheme.of(context).fontGyColor3.withOpacity(0.4), + ), Padding( padding: const EdgeInsets.only(left: 2), child: Icon( TDIcons.chevron_right, - color: TDTheme.of(context).fontGyColor3.withOpacity(0.4),), + color: TDTheme.of(context).fontGyColor3.withOpacity(0.4), + ), ), ], ), ), ], ), - const TDDivider(margin: EdgeInsets.only(left: 16, ),) + const TDDivider( + margin: EdgeInsets.only( + left: 16, + ), + ) ], ), ); @@ -128,7 +148,6 @@ class _TDFormItemState extends State { children: [ TDInput( leftLabel: widget.label, - required: true, controller: widget.controller, backgroundColor: Colors.white, hintText: widget.help, @@ -150,13 +169,13 @@ class _TDFormItemState extends State { backgroundColor: Colors.white, rightBtn: browseOn ? Icon( - TDIcons.browse, - color: TDTheme.of(context).fontGyColor3, - ) + TDIcons.browse, + color: TDTheme.of(context).fontGyColor3, + ) : Icon( - TDIcons.browse_off, - color: TDTheme.of(context).fontGyColor3, - ), + TDIcons.browse_off, + color: TDTheme.of(context).fontGyColor3, + ), onBtnTap: () { setState(() { browseOn = !browseOn; @@ -169,48 +188,61 @@ class _TDFormItemState extends State { ), ], ); - } else if(widget.name == 'gender'){ - return TDRadioGroup( - selectId: 'index:1', - direction: Axis.horizontal, - directionalTdRadios: const [ - TDRadio( - id: '0', - title: '男', - radioStyle: TDRadioStyle.circle, - showDivider: false, - ), - TDRadio( - id: '1', - title: '女', - radioStyle: TDRadioStyle.circle, - showDivider: false, - ), - TDRadio( - id: '2', - title: '保密', - radioStyle: TDRadioStyle.circle, - showDivider: false, + } else if (widget.name == 'radios') { + final theme = TDTheme.of(context); + return Container( + height: 80.0, + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // 左侧的文本 + TDText( + widget.label ?? '', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(width: 16), // 间隔 + // 右侧的单选按钮组,使用 Expanded 包裹 + Expanded( + child: TDRadioGroup( + selectId: 'index:1', + direction: Axis.horizontal, + directionalTdRadios: widget.radios.entries.map((entry) { + return TDRadio( + id: entry.key, + title: entry.value, + radioStyle: TDRadioStyle.circle, + showDivider: false, + ); + }).toList(), + ), + ), + ], ), - ], + ), ); - } else if(widget.name == 'date'){ - return GestureDetector( - onTap: (){ - TDPicker.showDatePicker(context, title: '选择时间', - onConfirm: (selected) { - setState(() { - widget.select = '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; - }); - Navigator.of(context).pop(); - }, - dateStart: [1999, 01, 01], - dateEnd: [2023, 12, 31], - initialDate: [2012, 1, 1]); + } else if (widget.name == 'date') { + return GestureDetector( + onTap: () { + TDPicker.showDatePicker(context, title: '选择时间', + onConfirm: (selected) { + setState(() { + widget.select = + '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + }); + Navigator.of(context).pop(); }, - child: buildSelectRow(context, widget.select, '选择时间'), - ); - }else if(widget.name == 'age'){ + dateStart: [1999, 01, 01], + dateEnd: [2023, 12, 31], + initialDate: [2012, 1, 1]); + }, + child: buildSelectRow(context, widget.select, '选择时间'), + ); + } else if (widget.name == 'age') { final theme = TDTheme.of(context); return Container( @@ -233,31 +265,47 @@ class _TDFormItemState extends State { ), ), ); - }else if(widget.name == 'local'){ + } else if (widget.name == 'local') { return GestureDetector( onTap: () { - TDCascader.showMultiCascader(context, title: '选择地址', data: widget.localData, initialData: _initData, theme: 'step', + TDCascader.showMultiCascader(context, + title: '选择地址', + data: widget.localData, + initialData: _initData, + theme: 'step', onChange: (List selectData) { - setState(() { - List result = []; - int len = selectData.length; - _initData = selectData[len - 1].value!; - selectData.forEach((element) { - result.add(element.label); - }); - _selected_1 = result.join('/'); - }); - }, onClose: () { - Navigator.of(context).pop(); + setState(() { + List result = []; + int len = selectData.length; + _initData = selectData[len - 1].value!; + selectData.forEach((element) { + result.add(element.label); }); + _selected_1 = result.join('/'); + }); + }, onClose: () { + Navigator.of(context).pop(); + }); }, child: _buildSelectRow(context, _selected_1, '选择地区'), ); + } else if (widget.name == 'textarea') { + return TDTextarea( + /// 背景颜色未完成 + backgroundColor: Colors.white, + controller: widget.controller, + label: widget.label, + hintText: widget.help, + maxLength: widget.maxLength, + indicator: widget.indicator, + onChanged: (value) { + setState(() {}); + }, + ); } return Column(); } - Widget _buildSelectRow(BuildContext context, String output, String title) { return Container( color: TDTheme.of(context).whiteColor1, @@ -277,27 +325,29 @@ class _TDFormItemState extends State { ), Expanded( child: Padding( - padding: const EdgeInsets.only(right: 16, left: 16), - child: Row( - children: [ - Expanded( - child: TDText( - output, - font: TDTheme.of(context).fontBodyLarge, - textColor: TDTheme.of(context).fontGyColor3.withOpacity(0.4), - maxLines: 1, - overflow: TextOverflow.ellipsis, - )), - Padding( - padding: const EdgeInsets.only(left: 2), - child: Icon( - TDIcons.chevron_right, - color: TDTheme.of(context).fontGyColor3.withOpacity(0.4), - ), - ), - ], + padding: const EdgeInsets.only(right: 16, left: 16), + child: Row( + children: [ + Expanded( + child: TDText( + output, + font: TDTheme.of(context).fontBodyLarge, + textColor: + TDTheme.of(context).fontGyColor3.withOpacity(0.4), + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + Padding( + padding: const EdgeInsets.only(left: 2), + child: Icon( + TDIcons.chevron_right, + color: + TDTheme.of(context).fontGyColor3.withOpacity(0.4), + ), ), - )), + ], + ), + )), ], ), const TDDivider( From 6f29591e51666c1bd8472d1507d1a974ab0b8b93 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Sun, 6 Oct 2024 11:03:31 +0800 Subject: [PATCH 08/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86Form=E7=9A=84=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 64 +++++++++++++------ .../lib/src/components/form/td_form.dart | 25 ++++---- .../components/form/td_form_inherited.dart | 18 ++++++ .../lib/src/components/form/td_form_item.dart | 10 +-- 4 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 tdesign-component/lib/src/components/form/td_form_inherited.dart diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 50ef3cab6..aadb0e096 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -15,14 +15,22 @@ class _TDFormPageState extends State { var controller = []; String selected_1 = ''; - Color verticalTextColor = Colors.black; - Color horizontalTextColor = Colors.red; - Color verticalButtonColor = Colors.blueGrey; - Color horizontalButtonColor = Colors.blue; + /// 设置按钮是否可点击状态 + /// true 表示处于 active 状态 + bool horizontalButton = false; + bool verticalButton = true; + + Color activeButtonColor = Color(0xFFF0F1FD); + Color defaultButtonColor = Color(0xFFE5E5E5); + + Color verticalTextColor = Color(0xFF1A1A1A); + Color horizontalTextColor = Color(0xFF0A58D9); + Color verticalButtonColor = Color(0xFFE5E5E5); + Color horizontalButtonColor = Color(0xFFF0F1FD); Map _radios = {"0": "男", "1": "女", "2": "保密"}; - List _data = [ + static const List _data = [ { "label": '北京市', "value": '110000', @@ -171,7 +179,7 @@ class _TDFormPageState extends State { maxLength: 500, indicator: true, ) - ]); + ], disabled: false); } /// 横 竖 排版模式切换 @@ -198,14 +206,21 @@ class _TDFormPageState extends State { ), onTap: () { setState(() { - print("____1"); - final currentVerticalColor = verticalButtonColor; - verticalButtonColor = horizontalButtonColor; - horizontalButtonColor = currentVerticalColor; + if (horizontalButton) { + /// 置换按钮状态 + horizontalButton = false; + verticalButton = true; - final currentTextColor = verticalTextColor; - verticalTextColor = horizontalTextColor; - horizontalTextColor = currentTextColor; + /// 置换按钮颜色 + final currentVerticalColor = verticalButtonColor; + verticalButtonColor = horizontalButtonColor; + horizontalButtonColor = currentVerticalColor; + + /// 置换文字颜色 + final currentTextColor = verticalTextColor; + verticalTextColor = horizontalTextColor; + horizontalTextColor = currentTextColor; + } }); }, ), @@ -222,14 +237,21 @@ class _TDFormPageState extends State { ), onTap: () { setState(() { - print("____2"); - final currentVerticalColor = verticalButtonColor; - verticalButtonColor = horizontalButtonColor; - horizontalButtonColor = currentVerticalColor; + if (verticalButton) { + /// 置换按钮状态 + horizontalButton = true; + verticalButton = false; + + /// 置换按钮颜色 + final currentVerticalColor = verticalButtonColor; + verticalButtonColor = horizontalButtonColor; + horizontalButtonColor = currentVerticalColor; - final currentTextColor = verticalTextColor; - verticalTextColor = horizontalTextColor; - horizontalTextColor = currentTextColor; + /// 置换文字颜色 + final currentTextColor = verticalTextColor; + verticalTextColor = horizontalTextColor; + horizontalTextColor = currentTextColor; + } }); }, ), @@ -267,7 +289,7 @@ class _TDFormPageState extends State { ], ); current = Padding( - padding: const EdgeInsets.symmetric(vertical: 8), + padding: const EdgeInsets.symmetric(vertical: 1), child: SizedBox( child: Container( child: Padding( diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index 6fdd5ffd1..4c7c40436 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:tdesign_flutter/src/components/form/td_form_inherited.dart'; import '../../../tdesign_flutter.dart'; class TDForm extends StatefulWidget { @@ -35,7 +36,7 @@ class TDForm extends StatefulWidget { final Object? data; /// 是否禁用整个表单 - final bool? disabled; + final bool disabled; /// 表单信息错误信息配置 final Object? errorMessage; @@ -80,16 +81,18 @@ class TDForm extends StatefulWidget { class _TDFormState extends State { @override Widget build(BuildContext context) { - return Container( - child: ListView.separated( - shrinkWrap: true, - itemCount: widget.items.length, - itemBuilder: (context, index) { - return widget.items[index]; - }, - separatorBuilder: (context, index) { - return SizedBox(height: 1); - }, + return TDFormInherited( + disabled: widget.disabled, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: widget.items + .map((item) => Column( + children: [ + item, + SizedBox(height: 1), + ], + )) + .toList(), ), ); } diff --git a/tdesign-component/lib/src/components/form/td_form_inherited.dart b/tdesign-component/lib/src/components/form/td_form_inherited.dart new file mode 100644 index 000000000..ac6c102dd --- /dev/null +++ b/tdesign-component/lib/src/components/form/td_form_inherited.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; + +class TDFormInherited extends InheritedWidget { + const TDFormInherited( + {required Widget child, required this.disabled, Key? key}) + : super(child: child, key: key); + + final bool disabled; + + @override + bool updateShouldNotify(covariant TDFormInherited oldWidget) { + return true; + } + + static TDFormInherited? of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } +} diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 03d3f95b3..71735384f 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -152,9 +152,6 @@ class _TDFormItemState extends State { backgroundColor: Colors.white, hintText: widget.help, ), - const SizedBox( - height: 16, - ), ], ); } else if (widget.name == 'password') { @@ -183,15 +180,11 @@ class _TDFormItemState extends State { }, needClear: false, ), - const SizedBox( - height: 16, - ), ], ); } else if (widget.name == 'radios') { final theme = TDTheme.of(context); return Container( - height: 80.0, decoration: BoxDecoration( color: theme.whiteColor1, ), @@ -205,8 +198,7 @@ class _TDFormItemState extends State { widget.label ?? '', style: const TextStyle(fontSize: 16), ), - const SizedBox(width: 16), // 间隔 - // 右侧的单选按钮组,使用 Expanded 包裹 + const SizedBox(width: 16), Expanded( child: TDRadioGroup( selectId: 'index:1', From a66f0e80f8d94090cef2487c4c565439ba590c67 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 7 Oct 2024 13:50:26 +0800 Subject: [PATCH 09/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86Form=E7=9A=84=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_search_bar_page.dart | 72 ++++++++++--------- .../lib/src/components/form/td_form_item.dart | 2 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/tdesign-component/example/lib/page/td_search_bar_page.dart b/tdesign-component/example/lib/page/td_search_bar_page.dart index 85cba87b0..cf2908cd5 100644 --- a/tdesign-component/example/lib/page/td_search_bar_page.dart +++ b/tdesign-component/example/lib/page/td_search_bar_page.dart @@ -19,27 +19,29 @@ class _TDSearchBarPageState extends State { @override Widget build(BuildContext context) { return ExamplePage( - title: tdTitle(), - desc: '用于一组预设数据中的选择。', - exampleCodeGroup: 'search', - backgroundColor: TDTheme.of(context).grayColor2, - children: [ - ExampleModule( - title: '组件类型', - children: [ - ExampleItem(desc: '基础搜索框', builder: _buildDefaultSearchBar), - ExampleItem(desc: '获取焦点后显示取消按钮', builder: _buildFocusSearchBar), - ], - ), - ExampleModule(title: '组件样式', children: [ - ExampleItem(desc: '搜索框形状', builder: _buildSearchBarWithShape), - ExampleItem(desc: '默认状态其他对齐方式', builder: _buildCenterSearchBar), - ]), - ], + title: tdTitle(), + desc: '用于一组预设数据中的选择。', + exampleCodeGroup: 'search', + backgroundColor: TDTheme.of(context).grayColor2, + children: [ + ExampleModule( + title: '组件类型', + children: [ + ExampleItem(desc: '基础搜索框', builder: _buildDefaultSearchBar), + ExampleItem(desc: '获取焦点后显示取消按钮', builder: _buildFocusSearchBar), + ], + ), + ExampleModule(title: '组件样式', children: [ + ExampleItem(desc: '搜索框形状', builder: _buildSearchBarWithShape), + ExampleItem(desc: '默认状态其他对齐方式', builder: _buildCenterSearchBar), + ]), + ], test: [ ExampleItem(desc: '获取焦点后显示自定义操作按钮', builder: _buildSearchBarWithAction), - ExampleItem(desc: '自定义获取焦点后显示按钮', builder: _buildFocusSearchBarWithAction), - ],); + ExampleItem( + desc: '自定义获取焦点后显示按钮', builder: _buildFocusSearchBarWithAction), + ], + ); } @Demo(group: 'search') @@ -141,7 +143,9 @@ class _TDSearchBarPageState extends State { }); }, ), - const SizedBox(height: 10,), + const SizedBox( + height: 10, + ), Container( padding: const EdgeInsets.only(left: 15), alignment: Alignment.centerLeft, @@ -152,7 +156,7 @@ class _TDSearchBarPageState extends State { ], ); } - + @Demo(group: 'search') Widget _buildFocusSearchBarWithAction(BuildContext context) { return TDSearchBar( @@ -160,19 +164,19 @@ class _TDSearchBarPageState extends State { action: '搜索', needCancel: true, controller: inputController, - onActionClick: () { - showGeneralDialog( - context: context, - pageBuilder: (BuildContext buildContext, Animation animation, - Animation secondaryAnimation) { - return TDConfirmDialog( - content: inputController.text.isNotEmpty - ? '搜索关键词:${inputController.text}' - : '搜索关键词为空', - ); - }, - ); - }, + // onActionClick: () { + // showGeneralDialog( + // context: context, + // pageBuilder: (BuildContext buildContext, Animation animation, + // Animation secondaryAnimation) { + // return TDConfirmDialog( + // content: inputController.text.isNotEmpty + // ? '搜索关键词:${inputController.text}' + // : '搜索关键词为空', + // ); + // }, + // ); + // }, ); } } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 71735384f..43b0f6fb1 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -284,7 +284,7 @@ class _TDFormItemState extends State { } else if (widget.name == 'textarea') { return TDTextarea( /// 背景颜色未完成 - backgroundColor: Colors.white, + backgroundColor: Colors.red, controller: widget.controller, label: widget.label, hintText: widget.help, From 2fe5516df5d0da454965ca966a2cb0f8c1c70026 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 8 Oct 2024 21:18:36 +0800 Subject: [PATCH 10/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86Form=E7=9A=84=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 3 +++ .../lib/src/components/form/td_form_item.dart | 23 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index aadb0e096..f99a34cdd 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -134,12 +134,15 @@ class _TDFormPageState extends State { label: '用户名', name: 'name', help: '请输入用户名', + additionInfo: '输入用户名', + inputPadding: 15.0, controller: controller[0], ), TDFormItem( label: '密码', name: 'password', help: '请输入密码', + inputPadding: 35.0, controller: controller[1], ), TDFormItem( diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 43b0f6fb1..3314b8b83 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -20,6 +20,8 @@ class TDFormItem extends StatefulWidget { this.showErrowMessage, this.maxLength, this.indicator, + this.additionInfo, + this.inputPadding = 10.0, Key? key, }) : localData = localData ?? const [], radios = radios ?? const {}, @@ -36,10 +38,16 @@ class TDFormItem extends StatefulWidget { /// 是否显示右箭头 final bool? arrow; + /// TDInput 框的辅助说明文字 + final String? additionInfo; + /// 表单说明内容 /// 表单的默认输入字符 final String? help; + /// input 框默认文本的左侧 padding + final double inputPadding; + /// 表单字段标签对齐方式: /// 左对齐、右对齐、顶部对齐 /// 默认使用 Form 的对齐方式,其优先级高于 Form.labelAlign @@ -147,10 +155,16 @@ class _TDFormItemState extends State { return Column( children: [ TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + contentPadding: + EdgeInsets.only(left: widget.inputPadding), // 左侧内边距20像素 + border: InputBorder.none, + ), leftLabel: widget.label, controller: widget.controller, backgroundColor: Colors.white, - hintText: widget.help, + additionInfo: widget.additionInfo, ), ], ); @@ -158,11 +172,16 @@ class _TDFormItemState extends State { return Column( children: [ TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + contentPadding: + EdgeInsets.only(left: widget.inputPadding), // 左侧内边距20像素 + border: InputBorder.none, + ), type: TDInputType.normal, controller: widget.controller, obscureText: !browseOn, leftLabel: widget.label, - hintText: widget.help, backgroundColor: Colors.white, rightBtn: browseOn ? Icon( From 4215751828435216d4711ba9cdf5e98ae81d1d64 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 14 Oct 2024 19:04:44 +0800 Subject: [PATCH 11/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=20Form=20=E7=9A=84?= =?UTF-8?q?=E7=AB=96=E7=9B=B4UI=20=E7=A6=81=E7=94=A8=E6=80=81=20=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E9=87=8D=E7=BD=AE=E6=8C=89=E9=92=AE=20TODO:=20?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=80=BB=E8=BE=91=20=E9=87=8D=E7=BD=AE?= =?UTF-8?q?=E9=80=BB=E8=BE=91=20Problem:=20TDTextare=20=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E9=97=AE=E9=A2=98=20TDRadioGroup=20=E9=AB=98?= =?UTF-8?q?=E5=BA=A6=E9=97=AE=E9=A2=98=20TDInput=20=E7=AB=96=E7=9B=B4?= =?UTF-8?q?=E6=80=81=20additionInfo=20=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20=E7=AB=96=E7=9B=B4=E6=80=81=E6=96=87=E5=AD=97?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=20padding=20=E9=97=AE=E9=A2=98=20=E7=BB=84?= =?UTF-8?q?=E7=9B=B8=E8=BF=9E=E9=80=89=E6=8B=A9=E5=99=A8=20=20=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E9=80=89=E6=8B=A9=E5=99=A8=20=E6=B2=A1=E6=9C=89=20?= =?UTF-8?q?=E7=A6=81=E7=94=A8=E6=80=81=20=E7=AB=96=E7=9B=B4=E6=80=81?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_button_page.dart | 7 +- .../example/lib/page/td_form_page.dart | 198 +++-- .../example/lib/page/td_input_page.dart | 11 +- .../lib/src/components/form/td_form.dart | 12 +- .../components/form/td_form_inherited.dart | 23 +- .../lib/src/components/form/td_form_item.dart | 678 ++++++++++++------ 6 files changed, 613 insertions(+), 316 deletions(-) diff --git a/tdesign-component/example/lib/page/td_button_page.dart b/tdesign-component/example/lib/page/td_button_page.dart index 6c539e7f0..7c31b9983 100644 --- a/tdesign-component/example/lib/page/td_button_page.dart +++ b/tdesign-component/example/lib/page/td_button_page.dart @@ -382,14 +382,15 @@ class _TDButtonPageState extends State { ExampleItem( ignoreCode: true, desc: '按钮中路由跳转', - builder: (context){ + builder: (context) { return TDButton( text: '点击跳转', size: TDButtonSize.large, // type: TDButtonType.text, shape: TDButtonShape.rectangle, - onTap: () async{ - var result = await Navigator.of(context).pushNamedAndRemoveUntil('divider',(router){ + onTap: () async { + var result = await Navigator.of(context) + .pushNamedAndRemoveUntil('divider', (router) { return true; }); print('pushNamedAndRemoveUntil result: $result'); diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index f99a34cdd..58f1fd078 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -15,6 +15,12 @@ class _TDFormPageState extends State { var controller = []; String selected_1 = ''; + /// form 禁用的状态 + bool _formDisableState = false; + + /// form 排列方式是否为水平 + bool _isFormHorizontal = true; + /// 设置按钮是否可点击状态 /// true 表示处于 active 状态 bool horizontalButton = false; @@ -112,80 +118,88 @@ class _TDFormPageState extends State { @override Widget build(BuildContext context) { return ExamplePage( - title: tdTitle(), - exampleCodeGroup: 'form', - desc: '基础表单', - backgroundColor: const Color(0xfff6f6f6), - children: [ - ExampleModule(title: '基础类型', children: [ - ExampleItem(desc: '基础表单', builder: _buildArrangementSwitch), - ExampleItem(desc: '', builder: _buildSwitchWithBase), - ExampleItem(builder: (BuildContext context) { - return CodeWrapper(builder: _buildForm); - }) - ]), - ]); + title: tdTitle(), + exampleCodeGroup: 'form', + desc: '基础表单', + backgroundColor: const Color(0xfff6f6f6), + children: [ + ExampleModule(title: '基础类型', children: [ + ExampleItem(desc: '基础表单', builder: _buildArrangementSwitch), + ExampleItem(desc: '', builder: _buildSwitchWithBase), + ExampleItem(builder: (BuildContext context) { + return CodeWrapper(builder: _buildForm); + }), + ExampleItem( + ignoreCode: true, + desc: '', + builder: (_) => CodeWrapper(builder: _buildCombinationButtons)), + ]), + ], + ); } @Demo(group: 'form') Widget _buildForm(BuildContext context) { - return TDForm(items: [ - TDFormItem( - label: '用户名', - name: 'name', - help: '请输入用户名', - additionInfo: '输入用户名', - inputPadding: 15.0, - controller: controller[0], - ), - TDFormItem( - label: '密码', - name: 'password', - help: '请输入密码', - inputPadding: 35.0, - controller: controller[1], - ), - TDFormItem( - label: '性别', - name: 'radios', + return TDForm( + disabled: _formDisableState, + isHoeizontal: _isFormHorizontal, + items: [ + TDFormItem( + label: '用户名', + name: 'name', + help: '请输入用户名', + additionInfo: '输入用户名', + labelWidth: 15.0, + controller: controller[0], + ), + TDFormItem( + label: '密码', + name: 'password', + help: '请输入密码', + labelWidth: 35.0, + controller: controller[1], + ), + TDFormItem( + label: '性别', + name: 'radios', - /// 扩展一下数量和选项内容 - radios: _radios, - ), - TDFormItem( - label: '生日', - name: 'date', + /// 扩展一下数量和选项内容 + radios: _radios, + ), + TDFormItem( + label: '生日', + name: 'date', - /// 引入需要的日期数据 - select: selected_1, - ), - TDFormItem( - label: '籍贯', - name: 'local', + /// 引入需要的日期数据 + select: selected_1, + ), + TDFormItem( + label: '籍贯', + name: 'local', - /// 引入需要的地点数据 - localData: _data, - ), - TDFormItem( - label: '年限', - name: 'age', + /// 引入需要的地点数据 + localData: _data, + ), + TDFormItem( + label: '年限', + name: 'stepper', - /// 为 TDStepper 预留其他设置 - ), - TDFormItem( - label: '个人简介', - name: 'textarea', - help: '请输入个人简介', - controller: controller[2], + /// 为 TDStepper 预留其他设置 + ), + TDFormItem( + label: '个人简介', + name: 'textarea', + help: '请输入个人简介', + controller: controller[2], - /// 为 TDTextarea 长文本其他参数做预留 API - maxLength: 500, - indicator: true, - ) - ], disabled: false); + /// 为 TDTextarea 长文本其他参数做预留 API + maxLength: 500, + indicator: true, + ) + ]); } - /// 横 竖 排版模式切换 + /// 横 竖 排版模式切换按钮 @Demo(group: 'form') Widget _buildArrangementSwitch(BuildContext buildContext) { final theme = TDTheme.of(context); @@ -223,6 +237,8 @@ class _TDFormPageState extends State { final currentTextColor = verticalTextColor; verticalTextColor = horizontalTextColor; horizontalTextColor = currentTextColor; + _isFormHorizontal = true; + print(_isFormHorizontal); } }); }, @@ -254,6 +270,9 @@ class _TDFormPageState extends State { final currentTextColor = verticalTextColor; verticalTextColor = horizontalTextColor; horizontalTextColor = currentTextColor; + + _isFormHorizontal = false; + print(_isFormHorizontal); } }); }, @@ -267,12 +286,19 @@ class _TDFormPageState extends State { Widget _buildSwitchWithBase(BuildContext context) { return _buildItem( context, - const TDSwitch(), + TDSwitch( + isOn: _formDisableState, + onChanged: (value) { + setState(() { + _formDisableState = value; + }); + return false; + }, + ), title: '禁用态', ); } - /// 每一项的封装 @Demo(group: 'switch') Widget _buildItem(BuildContext context, Widget switchItem, {String? title, String? desc}) { @@ -306,4 +332,46 @@ class _TDFormPageState extends State { ); return Column(mainAxisSize: MainAxisSize.min, children: [current]); } + + /// 提交按钮 + @Demo(group: 'button') + Widget _buildCombinationButtons(BuildContext context) { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + SizedBox( + width: 16, + ), + Expanded( + child: TDButton( + text: '提交', + size: TDButtonSize.large, + type: TDButtonType.fill, + theme: TDButtonTheme.primary, + shape: TDButtonShape.rectangle, + )), + SizedBox( + width: 16, + ), + Expanded( + child: TDButton( + text: '重置', + size: TDButtonSize.large, + type: TDButtonType.fill, + shape: TDButtonShape.rectangle, + theme: TDButtonTheme.defaultTheme, + )), + SizedBox( + width: 16, + ), + ], + )), + ); + } } diff --git a/tdesign-component/example/lib/page/td_input_page.dart b/tdesign-component/example/lib/page/td_input_page.dart index 77c65bb5d..6d85ea198 100644 --- a/tdesign-component/example/lib/page/td_input_page.dart +++ b/tdesign-component/example/lib/page/td_input_page.dart @@ -72,7 +72,8 @@ class _TDInputViewPageState extends State { ExampleItem(desc: '带操作输入框', builder: _basicTypeWithHandleIconOne), ExampleItem(builder: _basicTypeWithHandleIconTwo), ExampleItem(builder: _basicTypeWithHandleIconThree), - ExampleItem(desc: '带图标输入框', builder: _basicTypeWithLeftIconLeftLabel), + ExampleItem( + desc: '带图标输入框', builder: _basicTypeWithLeftIconLeftLabel), ExampleItem(builder: _basicTypeWithLeftIcon), ExampleItem(desc: '特定类型输入框', builder: _specialTypePassword), ExampleItem(builder: _specialTypeVerifyCode), @@ -104,7 +105,8 @@ class _TDInputViewPageState extends State { ExampleItem(desc: '长文本样式', builder: _customLongTextStyle), ExampleItem(desc: '隐藏底部分割线', builder: _hideBottomDivider), ExampleItem(desc: '自定义高度-使用SizeBox', builder: _customHeight), - ExampleItem(desc: '获取焦点时点击外部区域事件响应-onTapOutside', builder: _onTapOutside) + ExampleItem( + desc: '获取焦点时点击外部区域事件响应-onTapOutside', builder: _onTapOutside) ], ); } @@ -138,7 +140,7 @@ class _TDInputViewPageState extends State { return Column( children: [ TDInput( - leftLabel: '标签文字', + leftLabel: '标签文字123', required: true, controller: controller[1], backgroundColor: Colors.white, @@ -513,7 +515,8 @@ class _TDInputViewPageState extends State { '${countDownText}(${_countdownTime}秒)', textColor: TDTheme.of(context).fontGyColor4, ) - : TDText(confirmText, textColor: TDTheme.of(context).brandNormalColor), + : TDText(confirmText, + textColor: TDTheme.of(context).brandNormalColor), ], ), ), diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index 4c7c40436..c6727fbf0 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -9,10 +9,11 @@ class TDForm extends StatefulWidget { this.colon = false, this.contentAlign = 'left', this.data, + this.isHoeizontal = true, this.disabled = false, this.errorMessage, this.labelAlign = 'right', - this.labelWidth = '81px', + this.labelWidth = 20.0, this.preventSubmitDefault = true, this.requiredMark = true, // 此处必填项有小问题 this.resetType = 'empty', @@ -35,6 +36,9 @@ class TDForm extends StatefulWidget { /// 表单数据 final Object? data; + /// 表单排列方式是否为 水平方向 + final bool isHoeizontal; + /// 是否禁用整个表单 final bool disabled; @@ -46,8 +50,8 @@ class TDForm extends StatefulWidget { /// 可选项: left/right/top final String? labelAlign; - /// 可以整体设置 label 标签宽度,默认为 81px - final String? labelWidth; + /// 可以整体设置 label 标签宽度 + final double? labelWidth; /// 是否阻止表单提交默认事件(表单提交默认事件会刷新页面) /// 设置为 true 可以避免刷新 @@ -83,6 +87,8 @@ class _TDFormState extends State { Widget build(BuildContext context) { return TDFormInherited( disabled: widget.disabled, + labelWidth: widget.labelWidth, + isHorizontal: widget.isHoeizontal, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: widget.items diff --git a/tdesign-component/lib/src/components/form/td_form_inherited.dart b/tdesign-component/lib/src/components/form/td_form_inherited.dart index ac6c102dd..86be39ee9 100644 --- a/tdesign-component/lib/src/components/form/td_form_inherited.dart +++ b/tdesign-component/lib/src/components/form/td_form_inherited.dart @@ -1,18 +1,25 @@ import 'package:flutter/cupertino.dart'; class TDFormInherited extends InheritedWidget { - const TDFormInherited( - {required Widget child, required this.disabled, Key? key}) - : super(child: child, key: key); - final bool disabled; + final double? labelWidth; + final bool isHorizontal; - @override - bool updateShouldNotify(covariant TDFormInherited oldWidget) { - return true; - } + const TDFormInherited({ + required Widget child, + required this.disabled, + required this.isHorizontal, + this.labelWidth, + }) : super(child: child); static TDFormInherited? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); } + + @override + bool updateShouldNotify(TDFormInherited oldWidget) { + return disabled != oldWidget.disabled || + labelWidth != oldWidget.labelWidth || + isHorizontal != oldWidget.isHorizontal; + } } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 3314b8b83..7aa7b631e 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:tdesign_flutter/src/components/form/td_form_inherited.dart'; import '../../../tdesign_flutter.dart'; class TDFormItem extends StatefulWidget { TDFormItem({ - /// 需要从 page 外部传入的参数 + // External parameters this.controller, this.select = '', List? localData, @@ -21,70 +22,57 @@ class TDFormItem extends StatefulWidget { this.maxLength, this.indicator, this.additionInfo, - this.inputPadding = 10.0, Key? key, }) : localData = localData ?? const [], radios = radios ?? const {}, super(key: key); - /// 表格内标签 内容填充 + // Form label content final String? label; - /// 表单内容对齐方式: - /// 左对齐、右对齐 - /// 可选项:left/right + // Form content alignment: 'left' or 'right' final String? contentAlign; - /// 是否显示右箭头 + // Whether to show the right arrow final bool? arrow; - /// TDInput 框的辅助说明文字 + // Auxiliary information for TDInput final String? additionInfo; - /// 表单说明内容 - /// 表单的默认输入字符 + // Help text for the form field final String? help; - /// input 框默认文本的左侧 padding - final double inputPadding; - - /// 表单字段标签对齐方式: - /// 左对齐、右对齐、顶部对齐 - /// 默认使用 Form 的对齐方式,其优先级高于 Form.labelAlign - /// 可选项: left/right.top + // Label alignment: 'left', 'right', or 'top' final String? labelAlign; - /// 可以整体调整标签宽度 - /// 优先级高于 Form.labelWidth - final String? labelWidth; + // Label width, overrides the Form's labelWidth if provided + final double? labelWidth; - /// 表格标识 + // Form field identifier final String? name; - /// 表格的 controller + // Controller for the form field var controller; - /// 日期选择需要展示的内容 + // Selected value for date picker or similar String select; - /// 组相联选择器需要的数据 + // Data for cascader or other selection widgets final List localData; - /// 单选框数据 + // Data for radio buttons final Map radios; - /// 是否显示必填符号 (*) - /// 优先级高于 Form.requiredMark + // Whether to display the required mark (*) final bool? requiredMark; - /// 表单字段校验规则 + // Validation rules for the form field final List? rules; - /// 校验不通过时,是否显示错误提示信息 - /// 优先级高于 Form.showErrowMessage + // Whether to show error messages final bool? showErrowMessage; - /// TDTextarea 预留API + // Properties for TDTextarea final int? maxLength; final bool? indicator; @@ -92,134 +80,304 @@ class TDFormItem extends StatefulWidget { _TDFormItemState createState() => _TDFormItemState(); } -Widget buildSelectRow(BuildContext context, String output, String title) { - return Container( - color: TDTheme.of(context).whiteColor1, - height: 56, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), - child: TDText( - title, - font: TDTheme.of(context).fontBodyLarge, - ), - ), - Padding( - padding: const EdgeInsets.only(right: 16), - child: Row( - children: [ - TDText( - output, - font: TDTheme.of(context).fontBodyLarge, - textColor: - TDTheme.of(context).fontGyColor3.withOpacity(0.4), - ), - Padding( - padding: const EdgeInsets.only(left: 2), - child: Icon( - TDIcons.chevron_right, - color: TDTheme.of(context).fontGyColor3.withOpacity(0.4), - ), - ), - ], - ), - ), - ], - ), - const TDDivider( - margin: EdgeInsets.only( - left: 16, - ), - ) - ], - ), - ); -} - class _TDFormItemState extends State { - /// 实现密码右侧的可见按钮 + double get LabelWidth { + final inherited = TDFormInherited.of(context); + final double defaultLabelWidth = 8.0; // Default label width + + // 优先使用 widget.labelWidth,如果不为空直接返回 + if (widget.labelWidth != null) { + return widget.labelWidth as double; + } + + // 如果 widget.labelWidth 为空,使用 inherited.labelWidth + if (inherited?.labelWidth != null) { + return inherited!.labelWidth as double; + } + + // 如果两者都为空,返回默认值 + return defaultLabelWidth; + } + + bool get FormState { + final inherited = TDFormInherited.of(context); + if (inherited?.disabled != null) { + return inherited!.disabled; + } + return false; + } + + bool get FormIsHorizontal { + final inherited = TDFormInherited.of(context); + if (inherited?.isHorizontal != null) { + return inherited!.isHorizontal; + } + return false; + } + bool browseOn = false; - /// 垂直联级选择器 String? _initData; String _selected_1 = ''; @override Widget build(BuildContext context) { - if (widget.name == 'name') { - return Column( - children: [ - TDInput( - inputDecoration: InputDecoration( - hintText: widget.help, - contentPadding: - EdgeInsets.only(left: widget.inputPadding), // 左侧内边距20像素 - border: InputBorder.none, - ), - leftLabel: widget.label, - controller: widget.controller, - backgroundColor: Colors.white, - additionInfo: widget.additionInfo, + if (FormIsHorizontal) { + if (widget.name == 'name') { + return TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + contentPadding: EdgeInsets.only(left: LabelWidth), + border: InputBorder.none, ), - ], - ); - } else if (widget.name == 'password') { - return Column( - children: [ - TDInput( - inputDecoration: InputDecoration( - hintText: widget.help, - contentPadding: - EdgeInsets.only(left: widget.inputPadding), // 左侧内边距20像素 - border: InputBorder.none, - ), - type: TDInputType.normal, - controller: widget.controller, - obscureText: !browseOn, - leftLabel: widget.label, - backgroundColor: Colors.white, - rightBtn: browseOn - ? Icon( - TDIcons.browse, - color: TDTheme.of(context).fontGyColor3, - ) - : Icon( - TDIcons.browse_off, - color: TDTheme.of(context).fontGyColor3, + leftLabel: widget.label, + controller: widget.controller, + backgroundColor: Colors.white, + additionInfo: widget.additionInfo, + readOnly: FormState, + ); + } else if (widget.name == 'password') { + return TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + contentPadding: EdgeInsets.only(left: LabelWidth), + border: InputBorder.none, + ), + type: TDInputType.normal, + controller: widget.controller, + obscureText: !browseOn, + leftLabel: widget.label, + backgroundColor: Colors.white, + rightBtn: browseOn + ? Icon( + TDIcons.browse, + color: TDTheme.of(context).fontGyColor3, + ) + : Icon( + TDIcons.browse_off, + color: TDTheme.of(context).fontGyColor3, + ), + onBtnTap: () { + setState(() { + browseOn = !browseOn; + }); + }, + needClear: false, + readOnly: FormState, + ); + } else if (widget.name == 'radios') { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TDText( + widget.label ?? '', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(width: 16), + Expanded( + child: TDRadioGroup( + selectId: 'index:1', + direction: Axis.horizontal, + directionalTdRadios: widget.radios.entries.map((entry) { + return TDRadio( + id: entry.key, + title: entry.value, + radioStyle: TDRadioStyle.circle, + showDivider: false, + enable: !FormState, + ); + }).toList(), ), - onBtnTap: () { + ), + ], + ), + ), + ); + } else if (widget.name == 'date') { + return GestureDetector( + onTap: () { + TDPicker.showDatePicker(context, title: '选择时间', + onConfirm: (selected) { setState(() { - browseOn = !browseOn; + widget.select = + '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; }); + Navigator.of(context).pop(); }, - needClear: false, + dateStart: [1999, 01, 01], + dateEnd: [2023, 12, 31], + initialDate: [2012, 1, 1]); + }, + child: buildSelectRow(context, widget.select, '选择时间'), + ); + } else if (widget.name == 'radios') { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, ), - ], - ); - } else if (widget.name == 'radios') { - final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - // 左侧的文本 - TDText( - widget.label ?? '', - style: const TextStyle(fontSize: 16), + child: Padding( + padding: EdgeInsets.all(16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TDText( + widget.label ?? '', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(width: 16), + Expanded( + child: TDRadioGroup( + selectId: 'index:1', + direction: Axis.horizontal, + directionalTdRadios: widget.radios.entries.map((entry) { + return TDRadio( + id: entry.key, + title: entry.value, + radioStyle: TDRadioStyle.circle, + showDivider: false, + enable: !FormState, + ); + }).toList(), + ), + ), + ], + ), + ), + ); + } else if (widget.name == 'local') { + return GestureDetector( + onTap: () { + TDCascader.showMultiCascader(context, + title: '选择地址', + data: widget.localData, + initialData: _initData, + theme: 'step', + onChange: (List selectData) { + setState(() { + List result = []; + int len = selectData.length; + _initData = selectData[len - 1].value!; + selectData.forEach((element) { + result.add(element.label); + }); + _selected_1 = result.join('/'); + }); + }, onClose: () { + Navigator.of(context).pop(); + }); + }, + child: _buildSelectRow(context, _selected_1, '选择地区'), + ); + } else if (widget.name == 'stepper') { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TDText( + widget.label, + style: TextStyle(fontSize: 16), + ), + TDStepper( + theme: TDStepperTheme.filled, + disabled: FormState, + ), + ], + ), + ), + ); + } else if (widget.name == 'textarea') { + return TDTextarea( + backgroundColor: Colors.red, + controller: widget.controller, + label: widget.label, + hintText: widget.help, + maxLength: widget.maxLength, + indicator: widget.indicator, + readOnly: FormState, + onChanged: (value) { + setState(() {}); + }, + ); + } + } else { + if (widget.name == 'name') { + return TDInput( + type: TDInputType.twoLine, + inputDecoration: InputDecoration( + hintText: widget.help, + border: InputBorder.none, + ), + leftLabel: widget.label, + controller: widget.controller, + backgroundColor: Colors.white, + + /// 竖直态的 TDInput 没用 additionInfo? + additionInfo: widget.additionInfo, + readOnly: FormState, + ); + } else if (widget.name == 'password') { + return Column( + children: [ + TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + // contentPadding: EdgeInsets.only(left: LabelWidth), + border: InputBorder.none, ), - const SizedBox(width: 16), - Expanded( - child: TDRadioGroup( + type: TDInputType.twoLine, + controller: widget.controller, + obscureText: !browseOn, + leftLabel: widget.label, + backgroundColor: Colors.white, + rightBtn: browseOn + ? Icon( + TDIcons.browse, + color: TDTheme.of(context).fontGyColor3, + ) + : Icon( + TDIcons.browse_off, + color: TDTheme.of(context).fontGyColor3, + ), + onBtnTap: () { + setState(() { + browseOn = !browseOn; + }); + }, + needClear: false, + readOnly: FormState, + ), + ], + ); + } else if (widget.name == 'radios') { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TDText( + widget.label ?? '', + style: const TextStyle(fontSize: 16), + ), + TDRadioGroup( selectId: 'index:1', direction: Axis.horizontal, directionalTdRadios: widget.radios.entries.map((entry) { @@ -228,96 +386,100 @@ class _TDFormItemState extends State { title: entry.value, radioStyle: TDRadioStyle.circle, showDivider: false, + enable: !FormState, ); }).toList(), ), - ), - ], + ], + ), ), - ), - ); - } else if (widget.name == 'date') { - return GestureDetector( - onTap: () { - TDPicker.showDatePicker(context, title: '选择时间', - onConfirm: (selected) { - setState(() { - widget.select = - '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; - }); - Navigator.of(context).pop(); + ); + } else if (widget.name == 'date') { + return GestureDetector( + onTap: () { + TDPicker.showDatePicker(context, title: '选择时间', + onConfirm: (selected) { + setState(() { + widget.select = + '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + }); + Navigator.of(context).pop(); + }, + dateStart: [1999, 01, 01], + dateEnd: [2023, 12, 31], + initialDate: [2012, 1, 1]); }, - dateStart: [1999, 01, 01], - dateEnd: [2023, 12, 31], - initialDate: [2012, 1, 1]); - }, - child: buildSelectRow(context, widget.select, '选择时间'), - ); - } else if (widget.name == 'age') { - final theme = TDTheme.of(context); - - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, // 左右分布 - children: [ - TDText( - widget.label, // 左侧的文本 - style: TextStyle(fontSize: 16), // 可根据需要设置样式 - ), - TDStepper( - theme: TDStepperTheme.filled, // 右侧的步进器 - ), - ], - ), - ), - ); - } else if (widget.name == 'local') { - return GestureDetector( - onTap: () { - TDCascader.showMultiCascader(context, - title: '选择地址', - data: widget.localData, - initialData: _initData, - theme: 'step', - onChange: (List selectData) { - setState(() { - List result = []; - int len = selectData.length; - _initData = selectData[len - 1].value!; - selectData.forEach((element) { - result.add(element.label); + child: buildSelectRow(context, widget.select, '选择时间'), + ); + } else if (widget.name == 'local') { + return GestureDetector( + onTap: () { + TDCascader.showMultiCascader(context, + title: '选择地址', + data: widget.localData, + initialData: _initData, + theme: 'step', + onChange: (List selectData) { + setState(() { + List result = []; + int len = selectData.length; + _initData = selectData[len - 1].value!; + selectData.forEach((element) { + result.add(element.label); + }); + _selected_1 = result.join('/'); }); - _selected_1 = result.join('/'); + }, onClose: () { + Navigator.of(context).pop(); }); - }, onClose: () { - Navigator.of(context).pop(); - }); - }, - child: _buildSelectRow(context, _selected_1, '选择地区'), - ); - } else if (widget.name == 'textarea') { - return TDTextarea( - /// 背景颜色未完成 - backgroundColor: Colors.red, - controller: widget.controller, - label: widget.label, - hintText: widget.help, - maxLength: widget.maxLength, - indicator: widget.indicator, - onChanged: (value) { - setState(() {}); - }, - ); + }, + child: _buildSelectRow(context, _selected_1, '选择地区'), + ); + } else if (widget.name == 'stepper') { + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, // 使内容左对齐 + children: [ + TDText( + widget.label, + style: TextStyle(fontSize: 16), + ), + SizedBox(height: 8), + TDStepper( + theme: TDStepperTheme.filled, + disabled: FormState, + ), + ], + ), + ), + ); + } else if (widget.name == 'textarea') { + return TDTextarea( + backgroundColor: Colors.red, + controller: widget.controller, + label: widget.label, + hintText: widget.help, + maxLength: widget.maxLength, + indicator: widget.indicator, + readOnly: FormState, + layout: TDTextareaLayout.vertical, + onChanged: (value) { + setState(() {}); + }, + ); + } } + return Column(); } - Widget _buildSelectRow(BuildContext context, String output, String title) { + Widget buildSelectRow(BuildContext context, String output, String title) { return Container( color: TDTheme.of(context).whiteColor1, height: 56, @@ -328,26 +490,22 @@ class _TDFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), + padding: EdgeInsets.only(left: 16, top: 16, bottom: 16), child: TDText( title, font: TDTheme.of(context).fontBodyLarge, ), ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 16, left: 16), + Padding( + padding: const EdgeInsets.only(right: 16), child: Row( children: [ - Expanded( - child: TDText( + TDText( output, font: TDTheme.of(context).fontBodyLarge, textColor: TDTheme.of(context).fontGyColor3.withOpacity(0.4), - maxLines: 1, - overflow: TextOverflow.ellipsis, - )), + ), Padding( padding: const EdgeInsets.only(left: 2), child: Icon( @@ -358,7 +516,61 @@ class _TDFormItemState extends State { ), ], ), - )), + ), + ], + ), + const TDDivider( + margin: EdgeInsets.only( + left: 16, + ), + ) + ], + ), + ); + } + + Widget _buildSelectRow(BuildContext context, String output, String title) { + return Container( + color: TDTheme.of(context).whiteColor1, + height: 56, + child: Stack( + alignment: Alignment.bottomCenter, + children: [ + Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 16, top: 16, bottom: 16), + child: TDText( + title, + font: TDTheme.of(context).fontBodyLarge, + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(right: 16, left: 16), + child: Row( + children: [ + Expanded( + child: TDText( + output, + font: TDTheme.of(context).fontBodyLarge, + textColor: + TDTheme.of(context).fontGyColor3.withOpacity(0.4), + maxLines: 1, + overflow: TextOverflow.ellipsis, + )), + Padding( + padding: const EdgeInsets.only(left: 2), + child: Icon( + TDIcons.chevron_right, + color: + TDTheme.of(context).fontGyColor3.withOpacity(0.4), + ), + ), + ], + ), + ), + ), ], ), const TDDivider( From 5136d404da3f944553bc02547a1f5ecb717ccff6 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 14 Oct 2024 19:20:47 +0800 Subject: [PATCH 12/25] =?UTF-8?q?TODO:=20=E6=8F=90=E4=BA=A4=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20=E9=87=8D=E7=BD=AE=E9=80=BB=E8=BE=91=20Problem:=20T?= =?UTF-8?q?DTextare=20=E8=83=8C=E6=99=AF=E9=A2=9C=E8=89=B2=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20TDRadioGroup=20=E9=AB=98=E5=BA=A6=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20TDInput=20=E7=AB=96=E7=9B=B4=E6=80=81=20additionInfo=20?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98=20=E7=AB=96?= =?UTF-8?q?=E7=9B=B4=E6=80=81=E6=96=87=E5=AD=97=E5=AF=B9=E9=BD=90=20paddin?= =?UTF-8?q?g=20=E9=97=AE=E9=A2=98=20=E7=BB=84=E7=9B=B8=E8=BF=9E=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8=20=20=E6=97=B6=E9=97=B4=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=99=A8=20=E6=B2=A1=E6=9C=89=20=E7=A6=81=E7=94=A8=E6=80=81=20?= =?UTF-8?q?=E7=AB=96=E7=9B=B4=E6=80=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 125 ++++++++++++------ .../lib/src/components/form/td_form.dart | 8 +- .../lib/src/components/form/td_form_item.dart | 66 ++++----- 3 files changed, 122 insertions(+), 77 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 58f1fd078..f45fb26c1 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -34,12 +34,12 @@ class _TDFormPageState extends State { Color verticalButtonColor = Color(0xFFE5E5E5); Color horizontalButtonColor = Color(0xFFF0F1FD); - Map _radios = {"0": "男", "1": "女", "2": "保密"}; + final Map _radios = {'0': '男', '1': '女', '3': '保密'}; static const List _data = [ { - "label": '北京市', - "value": '110000', + 'label': '北京市', + 'value': '110000', "children": [ { "value": '110100', @@ -109,7 +109,7 @@ class _TDFormPageState extends State { @override void initState() { - for (var i = 0; i < 28; i++) { + for (var i = 0; i < 3; i++) { controller.add(TextEditingController()); } super.initState(); @@ -142,7 +142,7 @@ class _TDFormPageState extends State { Widget _buildForm(BuildContext context) { return TDForm( disabled: _formDisableState, - isHoeizontal: _isFormHorizontal, + isHorizontal: _isFormHorizontal, items: [ TDFormItem( label: '用户名', @@ -244,7 +244,7 @@ class _TDFormPageState extends State { }, ), ), - SizedBox(width: 8), + const SizedBox(width: 8), Expanded( child: TDButton( text: '竖直排布', @@ -337,41 +337,82 @@ class _TDFormPageState extends State { @Demo(group: 'button') Widget _buildCombinationButtons(BuildContext context) { final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - SizedBox( - width: 16, - ), - Expanded( - child: TDButton( - text: '提交', - size: TDButtonSize.large, - type: TDButtonType.fill, - theme: TDButtonTheme.primary, - shape: TDButtonShape.rectangle, - )), - SizedBox( - width: 16, - ), - Expanded( - child: TDButton( - text: '重置', - size: TDButtonSize.large, - type: TDButtonType.fill, - shape: TDButtonShape.rectangle, - theme: TDButtonTheme.defaultTheme, - )), - SizedBox( - width: 16, - ), - ], - )), - ); + if (!_formDisableState) { + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: const Padding( + padding: EdgeInsets.all(16), + child: Row( + children: [ + SizedBox( + width: 16, + ), + Expanded( + child: TDButton( + text: '提交', + size: TDButtonSize.large, + type: TDButtonType.fill, + theme: TDButtonTheme.primary, + shape: TDButtonShape.rectangle, + )), + SizedBox( + width: 16, + ), + Expanded( + child: TDButton( + text: '重置', + size: TDButtonSize.large, + type: TDButtonType.fill, + shape: TDButtonShape.rectangle, + theme: TDButtonTheme.defaultTheme, + )), + SizedBox( + width: 16, + ), + ], + )), + ); + } else { + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: const Padding( + padding: EdgeInsets.all(16), + child: Row( + children: [ + SizedBox( + width: 16, + ), + Expanded( + child: TDButton( + text: '提交', + size: TDButtonSize.large, + type: TDButtonType.fill, + theme: TDButtonTheme.primary, + shape: TDButtonShape.rectangle, + disabled: true, + )), + SizedBox( + width: 16, + ), + Expanded( + child: TDButton( + text: '重置', + size: TDButtonSize.large, + type: TDButtonType.fill, + shape: TDButtonShape.rectangle, + theme: TDButtonTheme.defaultTheme, + disabled: true, + )), + SizedBox( + width: 16, + ), + ], + )), + ); + } } } diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index c6727fbf0..5f815c17f 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:tdesign_flutter/src/components/form/td_form_inherited.dart'; +import 'td_form_inherited.dart'; import '../../../tdesign_flutter.dart'; class TDForm extends StatefulWidget { @@ -9,7 +9,7 @@ class TDForm extends StatefulWidget { this.colon = false, this.contentAlign = 'left', this.data, - this.isHoeizontal = true, + this.isHorizontal = true, this.disabled = false, this.errorMessage, this.labelAlign = 'right', @@ -37,7 +37,7 @@ class TDForm extends StatefulWidget { final Object? data; /// 表单排列方式是否为 水平方向 - final bool isHoeizontal; + final bool isHorizontal; /// 是否禁用整个表单 final bool disabled; @@ -88,7 +88,7 @@ class _TDFormState extends State { return TDFormInherited( disabled: widget.disabled, labelWidth: widget.labelWidth, - isHorizontal: widget.isHoeizontal, + isHorizontal: widget.isHorizontal, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: widget.items diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 7aa7b631e..a0a0fe428 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -1,14 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:tdesign_flutter/src/components/form/td_form_inherited.dart'; +import 'td_form_inherited.dart'; import '../../../tdesign_flutter.dart'; class TDFormItem extends StatefulWidget { TDFormItem({ - // External parameters - this.controller, - this.select = '', - List? localData, - Map? radios, this.label, this.name, this.arrow = false, @@ -22,58 +17,65 @@ class TDFormItem extends StatefulWidget { this.maxLength, this.indicator, this.additionInfo, + this.controller, + this.select = '', + List? localData, + Map? radios, Key? key, }) : localData = localData ?? const [], radios = radios ?? const {}, super(key: key); - // Form label content + /// 表单项标签内容 final String? label; - // Form content alignment: 'left' or 'right' + /// 表单内容对齐方式:'left' 或 'right' final String? contentAlign; - // Whether to show the right arrow + /// 是否显示右侧箭头 final bool? arrow; - // Auxiliary information for TDInput + /// TDInput的辅助信息 final String? additionInfo; - // Help text for the form field + /// TDInput 默认显示文字 final String? help; - // Label alignment: 'left', 'right', or 'top' + /// 标签对齐方式:'left', 'right', 或 'top' final String? labelAlign; - // Label width, overrides the Form's labelWidth if provided + /// 标签宽度,如果提供则覆盖Form的labelWidth final double? labelWidth; - // Form field identifier + /// 表单项标识符 final String? name; - // Controller for the form field + /// Input 控制器 var controller; - // Selected value for date picker or similar + /// 选择器 适用于日期选择器等 String select; - // Data for cascader or other selection widgets + /// 传入数据 适用于级联选择器等 final List localData; - // Data for radio buttons + /// 单选按钮数据 + /// < 序号 , 名称 > final Map radios; - // Whether to display the required mark (*) + /// 是否显示必填标记(*) final bool? requiredMark; - // Validation rules for the form field + /// 表单项验证规则 final List? rules; - // Whether to show error messages + /// 是否显示错误信息 final bool? showErrowMessage; - // Properties for TDTextarea + /// TDTextarea的属性,最大长度 final int? maxLength; + + /// TDTextarea的属性,指示器 final bool? indicator; @override @@ -283,13 +285,13 @@ class _TDFormItemState extends State { color: theme.whiteColor1, ), child: Padding( - padding: EdgeInsets.all(16), + padding: const EdgeInsets.all(16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TDText( widget.label, - style: TextStyle(fontSize: 16), + style: const TextStyle(fontSize: 16), ), TDStepper( theme: TDStepperTheme.filled, @@ -369,7 +371,7 @@ class _TDFormItemState extends State { color: theme.whiteColor1, ), child: Padding( - padding: EdgeInsets.all(16), + padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -377,6 +379,7 @@ class _TDFormItemState extends State { widget.label ?? '', style: const TextStyle(fontSize: 16), ), + const SizedBox(width: 20), TDRadioGroup( selectId: 'index:1', direction: Axis.horizontal, @@ -442,15 +445,15 @@ class _TDFormItemState extends State { color: theme.whiteColor1, ), child: Padding( - padding: EdgeInsets.all(16), + padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, // 使内容左对齐 children: [ TDText( widget.label, - style: TextStyle(fontSize: 16), + style: const TextStyle(fontSize: 16), ), - SizedBox(height: 8), + const SizedBox(height: 8), TDStepper( theme: TDStepperTheme.filled, disabled: FormState, @@ -476,7 +479,8 @@ class _TDFormItemState extends State { } } - return Column(); + /// TODO: 构建错误的提示页面 + return const Column(); } Widget buildSelectRow(BuildContext context, String output, String title) { @@ -490,7 +494,7 @@ class _TDFormItemState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( - padding: EdgeInsets.only(left: 16, top: 16, bottom: 16), + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), child: TDText( title, font: TDTheme.of(context).fontBodyLarge, @@ -539,7 +543,7 @@ class _TDFormItemState extends State { Row( children: [ Padding( - padding: EdgeInsets.only(left: 16, top: 16, bottom: 16), + padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), child: TDText( title, font: TDTheme.of(context).fontBodyLarge, From 8ff8b1103f60bca816d971bc41c50cf24d4b2dfe Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 14 Oct 2024 19:22:08 +0800 Subject: [PATCH 13/25] =?UTF-8?q?TODO:=20=E6=8F=90=E4=BA=A4=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20=E9=87=8D=E7=BD=AE=E9=80=BB=E8=BE=91=20Problem:=20T?= =?UTF-8?q?DTextare=20=E8=83=8C=E6=99=AF=E9=A2=9C=E8=89=B2=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20TDRadioGroup=20=E9=AB=98=E5=BA=A6=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20TDInput=20=E7=AB=96=E7=9B=B4=E6=80=81=20additionInfo=20?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98=20=E7=AB=96?= =?UTF-8?q?=E7=9B=B4=E6=80=81=E6=96=87=E5=AD=97=E5=AF=B9=E9=BD=90=20paddin?= =?UTF-8?q?g=20=E9=97=AE=E9=A2=98=20=E7=BB=84=E7=9B=B8=E8=BF=9E=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8=20=20=E6=97=B6=E9=97=B4=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=99=A8=20=E6=B2=A1=E6=9C=89=20=E7=A6=81=E7=94=A8=E6=80=81=20?= =?UTF-8?q?=E7=AB=96=E7=9B=B4=E6=80=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tdesign-component/example/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdesign-component/example/android/build.gradle b/tdesign-component/example/android/build.gradle index 53e7c1ac5..38f569bae 100644 --- a/tdesign-component/example/android/build.gradle +++ b/tdesign-component/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.9.0' + ext.kotlin_version = '1.6.21' ext { From b1ec23648e27e672218f4eef2737d30d644ca4d5 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 22 Oct 2024 10:54:05 +0800 Subject: [PATCH 14/25] =?UTF-8?q?TODO:=20=E6=96=B0=E5=A2=9E=20TDRated=20?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E7=A8=BF=E5=AF=B9=E6=AF=94=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=BB=84=E4=BB=B6=20API=20=E8=A1=A5=E5=85=A8=20Proble?= =?UTF-8?q?m:=20TDTextare=20=E8=83=8C=E6=99=AF=E9=A2=9C=E8=89=B2=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20TDRadioGroup=20=E9=AB=98=E5=BA=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 竖直态文字对齐 padding 问题 组相连选择器 时间选择器 没有 禁用态 竖直态问题 --- .../example/android/build.gradle | 2 +- .../example/lib/page/td_form_page.dart | 16 +- .../lib/src/components/form/td_form_item.dart | 639 +++++++++--------- 3 files changed, 317 insertions(+), 340 deletions(-) diff --git a/tdesign-component/example/android/build.gradle b/tdesign-component/example/android/build.gradle index 38f569bae..53e7c1ac5 100644 --- a/tdesign-component/example/android/build.gradle +++ b/tdesign-component/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.21' + ext.kotlin_version = '1.9.0' ext { diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index f45fb26c1..bb3bc9d4e 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -146,49 +146,49 @@ class _TDFormPageState extends State { items: [ TDFormItem( label: '用户名', - name: 'name', + type: TDFormItemType.input, help: '请输入用户名', - additionInfo: '输入用户名', + // additionInfo: '输入用户名', labelWidth: 15.0, controller: controller[0], ), TDFormItem( label: '密码', - name: 'password', + type: TDFormItemType.password, help: '请输入密码', labelWidth: 35.0, controller: controller[1], ), TDFormItem( label: '性别', - name: 'radios', + type: TDFormItemType.radios, /// 扩展一下数量和选项内容 radios: _radios, ), TDFormItem( label: '生日', - name: 'date', + type: TDFormItemType.dateTimePicker, /// 引入需要的日期数据 select: selected_1, ), TDFormItem( label: '籍贯', - name: 'local', + type: TDFormItemType.cascader, /// 引入需要的地点数据 localData: _data, ), TDFormItem( label: '年限', - name: 'stepper', + type: TDFormItemType.stepper, /// 为 TDStepper 预留其他设置 ), TDFormItem( label: '个人简介', - name: 'textarea', + type: TDFormItemType.textarea, help: '请输入个人简介', controller: controller[2], diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index a0a0fe428..83b51e1ec 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -4,8 +4,8 @@ import '../../../tdesign_flutter.dart'; class TDFormItem extends StatefulWidget { TDFormItem({ + required this.type, this.label, - this.name, this.arrow = false, this.contentAlign = 'left', this.help, @@ -29,6 +29,9 @@ class TDFormItem extends StatefulWidget { /// 表单项标签内容 final String? label; + /// 表格单元需要使用的组件类型 + final TDFormItemType type; + /// 表单内容对齐方式:'left' 或 'right' final String? contentAlign; @@ -47,9 +50,6 @@ class TDFormItem extends StatefulWidget { /// 标签宽度,如果提供则覆盖Form的labelWidth final double? labelWidth; - /// 表单项标识符 - final String? name; - /// Input 控制器 var controller; @@ -82,6 +82,17 @@ class TDFormItem extends StatefulWidget { _TDFormItemState createState() => _TDFormItemState(); } +/// 表格单元选用组件类型的枚举 +enum TDFormItemType { + input, + password, + radios, + dateTimePicker, + cascader, + stepper, + textarea +} + class _TDFormItemState extends State { double get LabelWidth { final inherited = TDFormInherited.of(context); @@ -125,118 +136,229 @@ class _TDFormItemState extends State { @override Widget build(BuildContext context) { if (FormIsHorizontal) { - if (widget.name == 'name') { - return TDInput( - inputDecoration: InputDecoration( - hintText: widget.help, - contentPadding: EdgeInsets.only(left: LabelWidth), - border: InputBorder.none, - ), - leftLabel: widget.label, - controller: widget.controller, - backgroundColor: Colors.white, - additionInfo: widget.additionInfo, - readOnly: FormState, - ); - } else if (widget.name == 'password') { - return TDInput( - inputDecoration: InputDecoration( - hintText: widget.help, - contentPadding: EdgeInsets.only(left: LabelWidth), - border: InputBorder.none, - ), - type: TDInputType.normal, - controller: widget.controller, - obscureText: !browseOn, - leftLabel: widget.label, - backgroundColor: Colors.white, - rightBtn: browseOn - ? Icon( - TDIcons.browse, - color: TDTheme.of(context).fontGyColor3, - ) - : Icon( - TDIcons.browse_off, - color: TDTheme.of(context).fontGyColor3, - ), - onBtnTap: () { - setState(() { - browseOn = !browseOn; - }); - }, - needClear: false, - readOnly: FormState, - ); - } else if (widget.name == 'radios') { - final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - TDText( - widget.label ?? '', - style: const TextStyle(fontSize: 16), - ), - const SizedBox(width: 16), - Expanded( - child: TDRadioGroup( - selectId: 'index:1', - direction: Axis.horizontal, - directionalTdRadios: widget.radios.entries.map((entry) { - return TDRadio( - id: entry.key, - title: entry.value, - radioStyle: TDRadioStyle.circle, - showDivider: false, - enable: !FormState, - ); - }).toList(), - ), - ), - ], + switch (widget.type) { + case TDFormItemType.input: + return TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + contentPadding: EdgeInsets.only(left: LabelWidth), + border: InputBorder.none, ), - ), - ); - } else if (widget.name == 'date') { - return GestureDetector( - onTap: () { - TDPicker.showDatePicker(context, title: '选择时间', - onConfirm: (selected) { + leftLabel: widget.label, + controller: widget.controller, + backgroundColor: Colors.white, + // additionInfo: widget.additionInfo, + readOnly: FormState, + ); + case TDFormItemType.password: + return TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + contentPadding: EdgeInsets.only(left: LabelWidth), + border: InputBorder.none, + ), + type: TDInputType.normal, + controller: widget.controller, + obscureText: !browseOn, + leftLabel: widget.label, + backgroundColor: Colors.white, + rightBtn: browseOn + ? Icon( + TDIcons.browse, + color: TDTheme.of(context).fontGyColor3, + ) + : Icon( + TDIcons.browse_off, + color: TDTheme.of(context).fontGyColor3, + ), + onBtnTap: () { setState(() { - widget.select = - '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + browseOn = !browseOn; }); - Navigator.of(context).pop(); }, - dateStart: [1999, 01, 01], - dateEnd: [2023, 12, 31], - initialDate: [2012, 1, 1]); - }, - child: buildSelectRow(context, widget.select, '选择时间'), - ); - } else if (widget.name == 'radios') { - final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: EdgeInsets.all(16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - TDText( - widget.label ?? '', - style: const TextStyle(fontSize: 16), + needClear: false, + readOnly: FormState, + ); + case TDFormItemType.radios: + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: EdgeInsets.all(16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TDText( + widget.label ?? '', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(width: 16), + Expanded( + child: TDRadioGroup( + selectId: 'index:1', + direction: Axis.horizontal, + directionalTdRadios: widget.radios.entries.map((entry) { + return TDRadio( + id: entry.key, + title: entry.value, + radioStyle: TDRadioStyle.circle, + showDivider: false, + enable: !FormState, + ); + }).toList(), + ), + ), + ], + ), + ), + ); + case TDFormItemType.dateTimePicker: + return GestureDetector( + onTap: () { + TDPicker.showDatePicker(context, title: '选择时间', + onConfirm: (selected) { + setState(() { + widget.select = + '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + }); + Navigator.of(context).pop(); + }, + dateStart: [1999, 01, 01], + dateEnd: [2023, 12, 31], + initialDate: [2012, 1, 1]); + }, + child: buildSelectRow(context, widget.select, '选择时间'), + ); + case TDFormItemType.cascader: + return GestureDetector( + onTap: () { + TDCascader.showMultiCascader(context, + title: '选择地址', + data: widget.localData, + initialData: _initData, + theme: 'step', + onChange: (List selectData) { + setState(() { + List result = []; + int len = selectData.length; + _initData = selectData[len - 1].value!; + selectData.forEach((element) { + result.add(element.label); + }); + _selected_1 = result.join('/'); + }); + }, onClose: () { + Navigator.of(context).pop(); + }); + }, + child: _buildSelectRow(context, _selected_1, '选择地区'), + ); + case TDFormItemType.stepper: + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TDText( + widget.label, + style: const TextStyle(fontSize: 16), + ), + TDStepper( + theme: TDStepperTheme.filled, + disabled: FormState, + ), + ], + ), + ), + ); + case TDFormItemType.textarea: + return TDTextarea( + backgroundColor: Colors.red, + controller: widget.controller, + label: widget.label, + hintText: widget.help, + maxLength: widget.maxLength, + indicator: widget.indicator, + readOnly: FormState, + onChanged: (value) { + setState(() {}); + }, + ); + } + } else { + switch (widget.type) { + case TDFormItemType.input: + return TDInput( + type: TDInputType.twoLine, + inputDecoration: InputDecoration( + hintText: widget.help, + border: InputBorder.none, + ), + leftLabel: widget.label, + controller: widget.controller, + backgroundColor: Colors.white, + + /// 竖直态的 TDInput 没用 additionInfo? + additionInfo: widget.additionInfo, + readOnly: FormState, + ); + case TDFormItemType.password: + return Column( + children: [ + TDInput( + inputDecoration: InputDecoration( + hintText: widget.help, + // contentPadding: EdgeInsets.only(left: LabelWidth), + border: InputBorder.none, ), - const SizedBox(width: 16), - Expanded( - child: TDRadioGroup( + type: TDInputType.twoLine, + controller: widget.controller, + obscureText: !browseOn, + leftLabel: widget.label, + backgroundColor: Colors.white, + rightBtn: browseOn + ? Icon( + TDIcons.browse, + color: TDTheme.of(context).fontGyColor3, + ) + : Icon( + TDIcons.browse_off, + color: TDTheme.of(context).fontGyColor3, + ), + onBtnTap: () { + setState(() { + browseOn = !browseOn; + }); + }, + needClear: false, + readOnly: FormState, + ), + ], + ); + case TDFormItemType.radios: + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TDText( + widget.label ?? '', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(width: 20), + TDRadioGroup( selectId: 'index:1', direction: Axis.horizontal, directionalTdRadios: widget.radios.entries.map((entry) { @@ -249,238 +371,93 @@ class _TDFormItemState extends State { ); }).toList(), ), - ), - ], - ), - ), - ); - } else if (widget.name == 'local') { - return GestureDetector( - onTap: () { - TDCascader.showMultiCascader(context, - title: '选择地址', - data: widget.localData, - initialData: _initData, - theme: 'step', - onChange: (List selectData) { - setState(() { - List result = []; - int len = selectData.length; - _initData = selectData[len - 1].value!; - selectData.forEach((element) { - result.add(element.label); - }); - _selected_1 = result.join('/'); - }); - }, onClose: () { - Navigator.of(context).pop(); - }); - }, - child: _buildSelectRow(context, _selected_1, '选择地区'), - ); - } else if (widget.name == 'stepper') { - final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - TDText( - widget.label, - style: const TextStyle(fontSize: 16), - ), - TDStepper( - theme: TDStepperTheme.filled, - disabled: FormState, - ), - ], - ), - ), - ); - } else if (widget.name == 'textarea') { - return TDTextarea( - backgroundColor: Colors.red, - controller: widget.controller, - label: widget.label, - hintText: widget.help, - maxLength: widget.maxLength, - indicator: widget.indicator, - readOnly: FormState, - onChanged: (value) { - setState(() {}); - }, - ); - } - } else { - if (widget.name == 'name') { - return TDInput( - type: TDInputType.twoLine, - inputDecoration: InputDecoration( - hintText: widget.help, - border: InputBorder.none, - ), - leftLabel: widget.label, - controller: widget.controller, - backgroundColor: Colors.white, - - /// 竖直态的 TDInput 没用 additionInfo? - additionInfo: widget.additionInfo, - readOnly: FormState, - ); - } else if (widget.name == 'password') { - return Column( - children: [ - TDInput( - inputDecoration: InputDecoration( - hintText: widget.help, - // contentPadding: EdgeInsets.only(left: LabelWidth), - border: InputBorder.none, + ], ), - type: TDInputType.twoLine, - controller: widget.controller, - obscureText: !browseOn, - leftLabel: widget.label, - backgroundColor: Colors.white, - rightBtn: browseOn - ? Icon( - TDIcons.browse, - color: TDTheme.of(context).fontGyColor3, - ) - : Icon( - TDIcons.browse_off, - color: TDTheme.of(context).fontGyColor3, - ), - onBtnTap: () { + ), + ); + case TDFormItemType.dateTimePicker: + return GestureDetector( + onTap: () { + TDPicker.showDatePicker(context, title: '选择时间', + onConfirm: (selected) { setState(() { - browseOn = !browseOn; + widget.select = + '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; }); + Navigator.of(context).pop(); }, - needClear: false, - readOnly: FormState, - ), - ], - ); - } else if (widget.name == 'radios') { - final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TDText( - widget.label ?? '', - style: const TextStyle(fontSize: 16), - ), - const SizedBox(width: 20), - TDRadioGroup( - selectId: 'index:1', - direction: Axis.horizontal, - directionalTdRadios: widget.radios.entries.map((entry) { - return TDRadio( - id: entry.key, - title: entry.value, - radioStyle: TDRadioStyle.circle, - showDivider: false, - enable: !FormState, - ); - }).toList(), - ), - ], - ), - ), - ); - } else if (widget.name == 'date') { - return GestureDetector( - onTap: () { - TDPicker.showDatePicker(context, title: '选择时间', - onConfirm: (selected) { - setState(() { - widget.select = - '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; - }); - Navigator.of(context).pop(); + dateStart: [1999, 01, 01], + dateEnd: [2023, 12, 31], + initialDate: [2012, 1, 1]); }, - dateStart: [1999, 01, 01], - dateEnd: [2023, 12, 31], - initialDate: [2012, 1, 1]); - }, - child: buildSelectRow(context, widget.select, '选择时间'), - ); - } else if (widget.name == 'local') { - return GestureDetector( - onTap: () { - TDCascader.showMultiCascader(context, - title: '选择地址', - data: widget.localData, - initialData: _initData, - theme: 'step', - onChange: (List selectData) { - setState(() { - List result = []; - int len = selectData.length; - _initData = selectData[len - 1].value!; - selectData.forEach((element) { - result.add(element.label); + child: buildSelectRow(context, widget.select, '选择时间'), + ); + case TDFormItemType.cascader: + return GestureDetector( + onTap: () { + TDCascader.showMultiCascader(context, + title: '选择地址', + data: widget.localData, + initialData: _initData, + theme: 'step', + onChange: (List selectData) { + setState(() { + List result = []; + int len = selectData.length; + _initData = selectData[len - 1].value!; + selectData.forEach((element) { + result.add(element.label); + }); + _selected_1 = result.join('/'); }); - _selected_1 = result.join('/'); + }, onClose: () { + Navigator.of(context).pop(); }); - }, onClose: () { - Navigator.of(context).pop(); - }); - }, - child: _buildSelectRow(context, _selected_1, '选择地区'), - ); - } else if (widget.name == 'stepper') { - final theme = TDTheme.of(context); - return Container( - decoration: BoxDecoration( - color: theme.whiteColor1, - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, // 使内容左对齐 - children: [ - TDText( - widget.label, - style: const TextStyle(fontSize: 16), - ), - const SizedBox(height: 8), - TDStepper( - theme: TDStepperTheme.filled, - disabled: FormState, - ), - ], + }, + child: _buildSelectRow(context, _selected_1, '选择地区'), + ); + case TDFormItemType.stepper: + final theme = TDTheme.of(context); + return Container( + decoration: BoxDecoration( + color: theme.whiteColor1, ), - ), - ); - } else if (widget.name == 'textarea') { - return TDTextarea( - backgroundColor: Colors.red, - controller: widget.controller, - label: widget.label, - hintText: widget.help, - maxLength: widget.maxLength, - indicator: widget.indicator, - readOnly: FormState, - layout: TDTextareaLayout.vertical, - onChanged: (value) { - setState(() {}); - }, - ); + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, // 使内容左对齐 + children: [ + TDText( + widget.label, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 8), + TDStepper( + theme: TDStepperTheme.filled, + disabled: FormState, + ), + ], + ), + ), + ); + case TDFormItemType.textarea: + return TDTextarea( + backgroundColor: Colors.red, + controller: widget.controller, + label: widget.label, + hintText: widget.help, + maxLength: widget.maxLength, + indicator: widget.indicator, + readOnly: FormState, + layout: TDTextareaLayout.vertical, + onChanged: (value) { + setState(() {}); + }, + ); } } /// TODO: 构建错误的提示页面 - return const Column(); } Widget buildSelectRow(BuildContext context, String output, String title) { From df878282b6b54e3d7c961a77d3cfae24903e3e64 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 22 Oct 2024 10:54:58 +0800 Subject: [PATCH 15/25] =?UTF-8?q?TODO:=20=E6=96=B0=E5=A2=9E=20TDRated=20?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E7=A8=BF=E5=AF=B9=E6=AF=94=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=BB=84=E4=BB=B6=20API=20=E8=A1=A5=E5=85=A8=20Proble?= =?UTF-8?q?m:=20TDTextare=20=E8=83=8C=E6=99=AF=E9=A2=9C=E8=89=B2=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20TDRadioGroup=20=E9=AB=98=E5=BA=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 竖直态文字对齐 padding 问题 组相连选择器 时间选择器 没有 禁用态 竖直态问题 --- tdesign-component/lib/src/components/form/td_form_item.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 83b51e1ec..07db67887 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -26,7 +26,7 @@ class TDFormItem extends StatefulWidget { radios = radios ?? const {}, super(key: key); - /// 表单项标签内容 + /// 表单项标签左侧展示的内容 final String? label; /// 表格单元需要使用的组件类型 From 03086a87b5aecb0358f0fd5eda0c417e9d985a08 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 22 Oct 2024 11:46:56 +0800 Subject: [PATCH 16/25] =?UTF-8?q?rebase=20=E5=88=86=E6=94=AF=20develop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tdesign-component/example/pubspec.lock | 569 +++++++++++++++++++++++++ 1 file changed, 569 insertions(+) diff --git a/tdesign-component/example/pubspec.lock b/tdesign-component/example/pubspec.lock index e69de29bb..f12b08469 100644 --- a/tdesign-component/example/pubspec.lock +++ b/tdesign-component/example/pubspec.lock @@ -0,0 +1,569 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + url: "https://pub.dev" + source: hosted + version: "64.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + url: "https://pub.dev" + source: hosted + version: "6.2.0" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + url: "https://pub.dev" + source: hosted + version: "1.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + dartx: + dependency: transitive + description: + name: dartx + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_easyrefresh: + dependency: transitive + description: + name: flutter_easyrefresh + sha256: "5d161ee5dcac34da9065116568147d742dd25fb9bff3b10024d9054b195087ad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + flutter_gen: + dependency: transitive + description: + name: flutter_gen + sha256: d7e4e57f606d73628b97765a67fdfb5a97e24cd2183e170afa8d1f62e48a9d5c + url: "https://pub.dev" + source: hosted + version: "5.8.0" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: "46ecf0e317413dd065547887c43f93f55e9653e83eb98dc13dd07d40dd225325" + url: "https://pub.dev" + source: hosted + version: "5.8.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + url: "https://pub.dev" + source: hosted + version: "1.0.4" + flutter_localizations: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + sha256: "21b085a1c185e46701373866144ced56cfb7a0c33f63c916bb8fe2d0c1491278" + url: "https://pub.dev" + source: hosted + version: "0.6.19" + flutter_slidable: + dependency: transitive + description: + name: flutter_slidable + sha256: "673403d2eeef1f9e8483bd6d8d92aae73b1d8bd71f382bc3930f699c731bc27c" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + flutter_swiper_null_safety: + dependency: "direct main" + description: + name: flutter_swiper_null_safety + sha256: "5a855e0080d035c08e82f8b7fd2f106344943a30c9ab483b2584860a2f22eaaf" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + hashcodes: + dependency: transitive + description: + name: hashcodes + sha256: "80f9410a5b3c8e110c4b7604546034749259f5d6dcca63e0d3c17c9258f1a651" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image_size_getter: + dependency: transitive + description: + name: image_size_getter + sha256: "0511799498340b70993d2dfb34b55a2247b5b801d75a6cdd4543acfcafdb12b0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + intl: + dependency: "direct main" + description: + name: intl + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + url: "https://pub.dev" + source: hosted + version: "0.18.0" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + lints: + dependency: transitive + description: + name: lints + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + url: "https://pub.dev" + source: hosted + version: "1.0.1" + markdown: + dependency: transitive + description: + name: markdown + sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd + url: "https://pub.dev" + source: hosted + version: "7.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + url: "https://pub.dev" + source: hosted + version: "5.4.0" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + tdesign_flutter: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.1.6" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + time: + dependency: transitive + description: + name: time + sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + win32: + dependency: transitive + description: + name: win32 + sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" + url: "https://pub.dev" + source: hosted + version: "5.0.9" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" From a33274321d4f5bb0598275cbce2c62a4e3555b53 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Tue, 22 Oct 2024 15:04:54 +0800 Subject: [PATCH 17/25] =?UTF-8?q?=E4=BC=98=E5=8C=96=20TDFormItem=20type=20?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E5=80=BC=20API=20=E6=B7=BB=E5=8A=A0=20TDRate?= =?UTF-8?q?=20=E8=BF=9B=E5=85=A5=E8=A1=A8=E5=8D=95=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 4 ++ .../lib/src/components/form/td_form_item.dart | 46 ++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index bb3bc9d4e..2fa075f61 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -186,6 +186,10 @@ class _TDFormPageState extends State { /// 为 TDStepper 预留其他设置 ), + TDFormItem( + label: '自我评价', + type: TDFormItemType.rate, + ), TDFormItem( label: '个人简介', type: TDFormItemType.textarea, diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 07db67887..cfa86ea7e 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -90,7 +90,8 @@ enum TDFormItemType { dateTimePicker, cascader, stepper, - textarea + rate, + textarea, } class _TDFormItemState extends State { @@ -278,6 +279,14 @@ class _TDFormItemState extends State { ), ), ); + case TDFormItemType.rate: + return TDCell( + title: widget.label, + noteWidget: TDRate( + value: 3, + allowHalf: true, + disabled: FormState, + )); case TDFormItemType.textarea: return TDTextarea( backgroundColor: Colors.red, @@ -296,8 +305,10 @@ class _TDFormItemState extends State { switch (widget.type) { case TDFormItemType.input: return TDInput( + spacer: TDInputSpacer(iconLabelSpace: 0), type: TDInputType.twoLine, inputDecoration: InputDecoration( + contentPadding: EdgeInsets.only(left: LabelWidth), hintText: widget.help, border: InputBorder.none, ), @@ -306,7 +317,7 @@ class _TDFormItemState extends State { backgroundColor: Colors.white, /// 竖直态的 TDInput 没用 additionInfo? - additionInfo: widget.additionInfo, + // additionInfo: widget.additionInfo, readOnly: FormState, ); case TDFormItemType.password: @@ -315,7 +326,7 @@ class _TDFormItemState extends State { TDInput( inputDecoration: InputDecoration( hintText: widget.help, - // contentPadding: EdgeInsets.only(left: LabelWidth), + contentPadding: EdgeInsets.only(left: LabelWidth), border: InputBorder.none, ), type: TDInputType.twoLine, @@ -417,15 +428,14 @@ class _TDFormItemState extends State { child: _buildSelectRow(context, _selected_1, '选择地区'), ); case TDFormItemType.stepper: - final theme = TDTheme.of(context); return Container( decoration: BoxDecoration( - color: theme.whiteColor1, + color: TDTheme.of(context).whiteColor1, ), child: Padding( padding: const EdgeInsets.all(16), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, // 使内容左对齐 + crossAxisAlignment: CrossAxisAlignment.start, children: [ TDText( widget.label, @@ -440,6 +450,30 @@ class _TDFormItemState extends State { ), ), ); + case TDFormItemType.rate: + return Container( + width: double.infinity, // 设置宽度为无限,横向占满父容器 + decoration: BoxDecoration( + color: TDTheme.of(context).whiteColor1, + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TDText( + widget.label, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 8), + TDRate( + value: 3, + allowHalf: true, + disabled: FormState, + ), + ], + ), + )); case TDFormItemType.textarea: return TDTextarea( backgroundColor: Colors.red, From 43bdafe2f850f22ae48de827d5b363811f52b9ac Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Thu, 24 Oct 2024 10:48:20 +0800 Subject: [PATCH 18/25] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20Input=20padding=20?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 86 +++++---- .../lib/src/components/form/td_form_item.dart | 57 +++--- .../lib/src/components/input/td_input.dart | 179 +++++++++++++----- 3 files changed, 214 insertions(+), 108 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 2fa075f61..f1b475b25 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -34,8 +34,10 @@ class _TDFormPageState extends State { Color verticalButtonColor = Color(0xFFE5E5E5); Color horizontalButtonColor = Color(0xFFF0F1FD); + /// radios 传入参数 final Map _radios = {'0': '男', '1': '女', '3': '保密'}; + /// 级联选择器 传入参数 static const List _data = [ { 'label': '北京市', @@ -107,6 +109,52 @@ class _TDFormPageState extends State { }, ]; + /// 表单校验规则 + final Map>> _rules = { + 'name': [ + { + 'validator': (String? val) => val != null && val.length == 8, + 'message': '只能输入8个字符英文', + }, + ], + 'password': [ + { + 'validator': (String? val) => val != null && val.length > 6, + 'message': '长度大于6个字符', + }, + ], + 'gender': [ + { + 'validator': (String? val) => val != null && val.isNotEmpty, + 'message': '不能为空', + }, + ], + 'birth': [ + { + 'validator': (String? val) => val != null && val.isNotEmpty, + 'message': '不能为空', + }, + ], + 'place': [ + { + 'validator': (String? val) => val != null && val.isNotEmpty, + 'message': '不能为空', + }, + ], + 'description': [ + { + 'validator': (int? val) => val != null && val > 3, + 'message': '分数过低会影响整体评价', + }, + ], + 'resume': [ + { + 'validator': (String? val) => val != null && val.isNotEmpty, + 'message': '不能为空', + }, + ], + }; + @override void initState() { for (var i = 0; i < 3; i++) { @@ -148,20 +196,23 @@ class _TDFormPageState extends State { label: '用户名', type: TDFormItemType.input, help: '请输入用户名', - // additionInfo: '输入用户名', - labelWidth: 15.0, + // additionInfo: '只能输入8个字符英文', + labelWidth: 43.0, controller: controller[0], + // requiredMark: true, ), TDFormItem( label: '密码', type: TDFormItemType.password, help: '请输入密码', - labelWidth: 35.0, + // additionInfo: '只能输入数字', + labelWidth: 60.0, controller: controller[1], ), TDFormItem( label: '性别', type: TDFormItemType.radios, + labelWidth: 50.0, /// 扩展一下数量和选项内容 radios: _radios, @@ -361,20 +412,6 @@ class _TDFormPageState extends State { theme: TDButtonTheme.primary, shape: TDButtonShape.rectangle, )), - SizedBox( - width: 16, - ), - Expanded( - child: TDButton( - text: '重置', - size: TDButtonSize.large, - type: TDButtonType.fill, - shape: TDButtonShape.rectangle, - theme: TDButtonTheme.defaultTheme, - )), - SizedBox( - width: 16, - ), ], )), ); @@ -399,21 +436,6 @@ class _TDFormPageState extends State { shape: TDButtonShape.rectangle, disabled: true, )), - SizedBox( - width: 16, - ), - Expanded( - child: TDButton( - text: '重置', - size: TDButtonSize.large, - type: TDButtonType.fill, - shape: TDButtonShape.rectangle, - theme: TDButtonTheme.defaultTheme, - disabled: true, - )), - SizedBox( - width: 16, - ), ], )), ); diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index cfa86ea7e..ca8e68b54 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -35,6 +35,7 @@ class TDFormItem extends StatefulWidget { /// 表单内容对齐方式:'left' 或 'right' final String? contentAlign; + /// TODO: /// 是否显示右侧箭头 final bool? arrow; @@ -149,6 +150,7 @@ class _TDFormItemState extends State { controller: widget.controller, backgroundColor: Colors.white, // additionInfo: widget.additionInfo, + // additionInfoColor: TDTheme.of(context).errorColor6, readOnly: FormState, ); case TDFormItemType.password: @@ -179,6 +181,8 @@ class _TDFormItemState extends State { }, needClear: false, readOnly: FormState, + // additionInfo: widget.additionInfo, + // additionInfoColor: TDTheme.of(context).errorColor6, ); case TDFormItemType.radios: final theme = TDTheme.of(context); @@ -195,7 +199,7 @@ class _TDFormItemState extends State { widget.label ?? '', style: const TextStyle(fontSize: 16), ), - const SizedBox(width: 16), + SizedBox(width: LabelWidth), Expanded( child: TDRadioGroup( selectId: 'index:1', @@ -308,10 +312,11 @@ class _TDFormItemState extends State { spacer: TDInputSpacer(iconLabelSpace: 0), type: TDInputType.twoLine, inputDecoration: InputDecoration( - contentPadding: EdgeInsets.only(left: LabelWidth), + contentPadding: EdgeInsets.only(left: 16), hintText: widget.help, border: InputBorder.none, ), + leftLabelSpace: 16, leftLabel: widget.label, controller: widget.controller, backgroundColor: Colors.white, @@ -326,9 +331,10 @@ class _TDFormItemState extends State { TDInput( inputDecoration: InputDecoration( hintText: widget.help, - contentPadding: EdgeInsets.only(left: LabelWidth), + contentPadding: EdgeInsets.only(left: 16), border: InputBorder.none, ), + leftLabelSpace: 16, type: TDInputType.twoLine, controller: widget.controller, obscureText: !browseOn, @@ -359,33 +365,34 @@ class _TDFormItemState extends State { decoration: BoxDecoration( color: theme.whiteColor1, ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TDText( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(16), // 仅作用于 TDText + child: TDText( widget.label ?? '', style: const TextStyle(fontSize: 16), ), - const SizedBox(width: 20), - TDRadioGroup( - selectId: 'index:1', - direction: Axis.horizontal, - directionalTdRadios: widget.radios.entries.map((entry) { - return TDRadio( - id: entry.key, - title: entry.value, - radioStyle: TDRadioStyle.circle, - showDivider: false, - enable: !FormState, - ); - }).toList(), - ), - ], - ), + ), + const SizedBox(width: 20), + TDRadioGroup( + selectId: 'index:1', + direction: Axis.horizontal, + directionalTdRadios: widget.radios.entries.map((entry) { + return TDRadio( + id: entry.key, + title: entry.value, + radioStyle: TDRadioStyle.circle, + showDivider: false, + enable: !FormState, + ); + }).toList(), + ), + ], ), ); + case TDFormItemType.dateTimePicker: return GestureDetector( onTap: () { diff --git a/tdesign-component/lib/src/components/input/td_input.dart b/tdesign-component/lib/src/components/input/td_input.dart index a24893103..bd56897b3 100644 --- a/tdesign-component/lib/src/components/input/td_input.dart +++ b/tdesign-component/lib/src/components/input/td_input.dart @@ -5,7 +5,14 @@ import 'package:flutter/services.dart'; import '../../../tdesign_flutter.dart'; -enum TDInputType { normal, twoLine, longText, special, normalMaxTwoLine, cardStyle } +enum TDInputType { + normal, + twoLine, + longText, + special, + normalMaxTwoLine, + cardStyle +} enum TDInputSize { small, large } @@ -87,9 +94,12 @@ class TDInput extends StatelessWidget { ((leftLabel == null && leftIcon == null && !(required ?? false)) ? 0 : ((leftLabel?.length == null ? 0 : leftLabel!.length) * - (leftLabelStyle != null ? (leftLabelStyle.fontSize ?? 16) : 16) + + (leftLabelStyle != null + ? (leftLabelStyle.fontSize ?? 16) + : 16) + 1 + - (leftIcon != null ? 1 : 0) * ((leftIcon is Icon) ? (leftIcon.size ?? 24) : 24)) + + (leftIcon != null ? 1 : 0) * + ((leftIcon is Icon) ? (leftIcon.size ?? 24) : 24)) + (required == true ? 1 : 0) * 14), super(key: key); @@ -273,16 +283,21 @@ class TDInput extends StatelessWidget { Widget buildNormalInput(BuildContext context) { var cardStyleDecoration = _getCardStylePreDecoration(context); - var hasLeftWidget = leftLabel != null || leftIcon != null || (required ?? false); + var hasLeftWidget = + leftLabel != null || leftIcon != null || (required ?? false); return Stack( alignment: Alignment.bottomCenter, children: [ Container( alignment: Alignment.centerLeft, - color: (cardStyleDecoration != null || decoration != null) ? null : backgroundColor, + color: (cardStyleDecoration != null || decoration != null) + ? null + : backgroundColor, decoration: cardStyleDecoration ?? decoration, child: Row( - crossAxisAlignment: additionInfo != '' ? CrossAxisAlignment.start : CrossAxisAlignment.center, + crossAxisAlignment: additionInfo != '' + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, children: [ Visibility( visible: hasLeftWidget, @@ -306,13 +321,16 @@ class TDInput extends StatelessWidget { child: Container( constraints: BoxConstraints(maxWidth: _leftLabelWidth), padding: EdgeInsets.only( - left: leftIcon != null ? (spacer.iconLabelSpace ?? 4) : 0, + left: leftIcon != null + ? (spacer.iconLabelSpace ?? 4) + : 0, top: getInputPadding(), bottom: getInputPadding()), child: TDText( leftLabel, maxLines: 2, - style: leftLabelStyle ?? const TextStyle(letterSpacing: 0), + style: leftLabelStyle ?? + const TextStyle(letterSpacing: 0), font: TDTheme.of(context).fontBodyLarge, fontWeight: FontWeight.w400, ), @@ -329,7 +347,8 @@ class TDInput extends StatelessWidget { child: TDText( '*', maxLines: 1, - style: TextStyle(color: TDTheme.of(context).errorColor6), + style: TextStyle( + color: TDTheme.of(context).errorColor6), font: TDTheme.of(context).fontBodyLarge, fontWeight: FontWeight.w400, ), @@ -343,7 +362,8 @@ class TDInput extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ TDInputView( - textStyle: textStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor1), + textStyle: textStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor1), readOnly: readOnly, autofocus: autofocus, obscureText: obscureText, @@ -360,25 +380,32 @@ class TDInput extends StatelessWidget { focusNode: focusNode, isCollapsed: true, textAlign: contentAlignment, - hintTextStyle: hintTextStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor3), + hintTextStyle: hintTextStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor3), cursorColor: cursorColor, textInputBackgroundColor: textInputBackgroundColor, controller: controller, contentPadding: contentPadding ?? EdgeInsets.only( left: spacer.labelInputSpace ?? 16, - right: spacer.inputRightSpace != null ? spacer.inputRightSpace! / 2 : 16, - bottom: additionInfo != '' ? 4 : getInputPadding(), + right: spacer.inputRightSpace != null + ? spacer.inputRightSpace! / 2 + : 16, + bottom: + additionInfo != '' ? 4 : getInputPadding(), top: getInputPadding()), inputAction: inputAction, ), Visibility( child: Padding( - padding: EdgeInsets.only(left: spacer.additionInfoSpace ?? 16, bottom: getInputPadding()), + padding: EdgeInsets.only( + left: spacer.additionInfoSpace ?? 16, + bottom: getInputPadding()), child: TDText( additionInfo, font: TDTheme.of(context).fontBodySmall, - textColor: additionInfoColor ?? TDTheme.of(context).fontGyColor3, + textColor: additionInfoColor ?? + TDTheme.of(context).fontGyColor3, ), ), visible: additionInfo != '', @@ -389,22 +416,31 @@ class TDInput extends StatelessWidget { Visibility( visible: rightWidget != null, child: Container( - margin: EdgeInsets.only(top: getInputPadding(), bottom: getInputPadding(), right: 16), + margin: EdgeInsets.only( + top: getInputPadding(), + bottom: getInputPadding(), + right: 16), child: rightWidget, ), ), Visibility( - visible: controller != null && controller!.text.isNotEmpty && needClear && rightWidget == null, + visible: controller != null && + controller!.text.isNotEmpty && + needClear && + rightWidget == null, child: GestureDetector( child: Container( margin: EdgeInsets.only( - left: spacer.inputRightSpace != null ? spacer.inputRightSpace! / 2 : 8, + left: spacer.inputRightSpace != null + ? spacer.inputRightSpace! / 2 + : 8, right: spacer.rightSpace ?? 16, top: additionInfo != '' ? getInputPadding() : 0), child: Icon( size: clearIconSize, TDIcons.close_circle_filled, - color: clearBtnColor ?? TDTheme.of(context).fontGyColor3, + color: + clearBtnColor ?? TDTheme.of(context).fontGyColor3, ), ), onTap: onClearTap ?? @@ -417,7 +453,9 @@ class TDInput extends StatelessWidget { onTap: onBtnTap, child: Container( margin: EdgeInsets.only( - left: spacer.inputRightSpace != null ? spacer.inputRightSpace! / 2 : 8, + left: spacer.inputRightSpace != null + ? spacer.inputRightSpace! / 2 + : 8, right: spacer.rightSpace ?? 16, top: additionInfo != '' ? getInputPadding() : 0), child: rightBtn, @@ -454,17 +492,20 @@ class TDInput extends StatelessWidget { case TDCardStyle.topTextWithBlueBorder: cardStyleDecoration = BoxDecoration( color: Colors.white, - border: Border.all(color: TDTheme.of(context).brandNormalColor, width: 1.5), + border: Border.all( + color: TDTheme.of(context).brandNormalColor, width: 1.5), borderRadius: BorderRadius.circular(6)); break; case TDCardStyle.errorStyle: cardStyleDecoration = BoxDecoration( color: Colors.white, - border: Border.all(color: TDTheme.of(context).errorColor6, width: 1.5), + border: Border.all( + color: TDTheme.of(context).errorColor6, width: 1.5), borderRadius: BorderRadius.circular(6)); break; default: - cardStyleDecoration = BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(6)); + cardStyleDecoration = BoxDecoration( + color: Colors.white, borderRadius: BorderRadius.circular(6)); break; } } @@ -489,14 +530,18 @@ class TDInput extends StatelessWidget { Visibility( visible: leftLabel != null, child: Container( - constraints: BoxConstraints(maxWidth: _leftLabelWidth + (leftLabelSpace ?? 12)), - padding: EdgeInsets.only(left: leftLabelSpace ?? 12.0, top: 10.0), + constraints: BoxConstraints( + maxWidth: + _leftLabelWidth + (leftLabelSpace ?? 12)), + padding: EdgeInsets.only( + left: leftLabelSpace ?? 12.0, top: 10.0), child: Column( children: [ TDText( leftLabel, maxLines: 2, - style: leftLabelStyle ?? const TextStyle(letterSpacing: 0), + style: leftLabelStyle ?? + const TextStyle(letterSpacing: 0), font: TDTheme.of(context).fontBodyLarge, fontWeight: FontWeight.w400, ), @@ -515,7 +560,8 @@ class TDInput extends StatelessWidget { child: TDText( '*', maxLines: 1, - style: TextStyle(color: TDTheme.of(context).errorColor6), + style: TextStyle( + color: TDTheme.of(context).errorColor6), font: TDTheme.of(context).fontBodyLarge, fontWeight: FontWeight.w400, ), @@ -536,7 +582,8 @@ class TDInput extends StatelessWidget { Expanded( flex: 1, child: TDInputView( - textStyle: textStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor1), + textStyle: textStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor1), readOnly: readOnly, autofocus: autofocus, obscureText: obscureText, @@ -551,30 +598,38 @@ class TDInput extends StatelessWidget { isCollapsed: true, maxLines: maxLines, focusNode: focusNode, - hintTextStyle: hintTextStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor3), + hintTextStyle: hintTextStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor3), cursorColor: cursorColor, textInputBackgroundColor: textInputBackgroundColor, controller: controller, contentPadding: contentPadding ?? EdgeInsets.only( - left: spacer.labelInputSpace ?? 16, - right: spacer.inputRightSpace != null ? spacer.inputRightSpace! / 2 : 8, + left: spacer.labelInputSpace ?? 16, + right: spacer.inputRightSpace != null + ? spacer.inputRightSpace! / 2 + : 8, ), inputAction: inputAction, ), ), Visibility( - visible: controller != null && controller!.text.isNotEmpty && needClear, + visible: controller != null && + controller!.text.isNotEmpty && + needClear, child: GestureDetector( child: Container( margin: EdgeInsets.only( - left: spacer.inputRightSpace != null ? spacer.inputRightSpace! / 2 : 8, - right: spacer.rightSpace ?? 16, + left: spacer.inputRightSpace != null + ? spacer.inputRightSpace! / 2 + : 8, + right: spacer.rightSpace ?? 16, ), child: Icon( size: clearIconSize, TDIcons.close_circle_filled, - color: clearBtnColor ?? TDTheme.of(context).fontGyColor3, + color: clearBtnColor ?? + TDTheme.of(context).fontGyColor3, ), ), onTap: onClearTap, @@ -585,8 +640,10 @@ class TDInput extends StatelessWidget { onTap: onBtnTap, child: Container( margin: EdgeInsets.only( - left: spacer.inputRightSpace != null ? spacer.inputRightSpace! / 2 : 8, - right: spacer.rightSpace ?? 16, + left: spacer.inputRightSpace != null + ? spacer.inputRightSpace! / 2 + : 8, + right: spacer.rightSpace ?? 16, ), child: rightBtn, ), @@ -624,7 +681,10 @@ class TDInput extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only(left: 16, top: getInputPadding(), bottom: getInputPadding()), + padding: EdgeInsets.only( + left: 16, + top: getInputPadding(), + bottom: getInputPadding()), child: TDText( leftLabel, maxLines: 2, @@ -642,7 +702,8 @@ class TDInput extends StatelessWidget { Expanded( flex: 1, child: TDInputView( - textStyle: textStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor1), + textStyle: textStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor1), readOnly: readOnly, autofocus: autofocus, obscureText: obscureText, @@ -652,15 +713,19 @@ class TDInput extends StatelessWidget { inputType: inputType, textAlign: textAlign, onChanged: onChanged, - inputFormatters: inputFormatters ?? [LengthLimitingTextInputFormatter(maxLength)], + inputFormatters: inputFormatters ?? + [LengthLimitingTextInputFormatter(maxLength)], inputDecoration: inputDecoration, maxLines: maxLines, focusNode: focusNode, - hintTextStyle: hintTextStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor3), + hintTextStyle: hintTextStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor3), cursorColor: cursorColor, textInputBackgroundColor: textInputBackgroundColor, controller: controller, - contentPadding: contentPadding ?? const EdgeInsets.only(left: 16, right: 16, top: 12, bottom: 12), + contentPadding: contentPadding ?? + const EdgeInsets.only( + left: 16, right: 16, top: 12, bottom: 12), inputAction: inputAction, ), ), @@ -692,8 +757,10 @@ class TDInput extends StatelessWidget { Visibility( visible: leftLabel != null, child: Padding( - padding: - EdgeInsets.only(left: leftLabelSpace ?? 16, top: getInputPadding(), bottom: getInputPadding()), + padding: EdgeInsets.only( + left: leftLabelSpace ?? 16, + top: getInputPadding(), + bottom: getInputPadding()), child: leftInfoWidth != null ? SizedBox( width: _leftLabelWidth, @@ -721,7 +788,8 @@ class TDInput extends StatelessWidget { child: Padding( padding: EdgeInsets.only(left: spacer.labelInputSpace!), child: TDInputView( - textStyle: textStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor1), + textStyle: textStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor1), readOnly: readOnly, autofocus: autofocus, obscureText: obscureText, @@ -735,14 +803,17 @@ class TDInput extends StatelessWidget { maxLines: maxLines, focusNode: focusNode, isCollapsed: true, - hintTextStyle: hintTextStyle ?? TextStyle(color: TDTheme.of(context).fontGyColor3), + hintTextStyle: hintTextStyle ?? + TextStyle(color: TDTheme.of(context).fontGyColor3), cursorColor: cursorColor, textInputBackgroundColor: textInputBackgroundColor, controller: controller, textAlign: textAlign, contentPadding: contentPadding ?? EdgeInsets.only( - right: spacer.inputRightSpace!, bottom: getInputPadding(), top: getInputPadding()), + right: spacer.inputRightSpace!, + bottom: getInputPadding(), + top: getInputPadding()), inputAction: inputAction, ), ), @@ -750,7 +821,10 @@ class TDInput extends StatelessWidget { Visibility( visible: rightWidget != null, child: Container( - margin: EdgeInsets.only(top: getInputPadding(), bottom: getInputPadding(), right: spacer.rightSpace!), + margin: EdgeInsets.only( + top: getInputPadding(), + bottom: getInputPadding(), + right: spacer.rightSpace!), child: rightWidget, ), ), @@ -841,7 +915,8 @@ class Chinese2Formatter extends TextInputFormatter { final _regExp = r'^[\u4E00-\u9FA5A-Za-z0-9_]+$'; @override - TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { var newValueLength = newValue.text.length; var count = 0; if (newValueLength == 0) { @@ -858,11 +933,13 @@ class Chinese2Formatter extends TextInputFormatter { return newValue.copyWith( text: text, composing: TextRange.empty, - selection: TextSelection.fromPosition(TextPosition(offset: i, affinity: TextAffinity.downstream))); + selection: TextSelection.fromPosition( + TextPosition(offset: i, affinity: TextAffinity.downstream))); } } } - if (newValueLength > 0 && RegExp(_regExp).firstMatch(newValue.text) != null) { + if (newValueLength > 0 && + RegExp(_regExp).firstMatch(newValue.text) != null) { if (newValueLength + count <= maxLength) { return newValue; } From 44d8709e7ee84c182f72c6a70cedccd74137da49 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Thu, 24 Oct 2024 16:22:05 +0800 Subject: [PATCH 19/25] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=80=BB=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=9A=84=E6=A0=A1=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 97 +++++++------- .../example/lib/page/td_input_page.dart | 2 +- .../lib/src/components/form/td_form.dart | 13 +- .../components/form/td_form_inherited.dart | 23 +++- .../lib/src/components/form/td_form_item.dart | 126 ++++++++++++++---- .../components/form/td_form_validation.dart | 23 ++++ tdesign-component/lib/tdesign_flutter.dart | 3 +- 7 files changed, 198 insertions(+), 89 deletions(-) create mode 100644 tdesign-component/lib/src/components/form/td_form_validation.dart diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index f1b475b25..6b01bb659 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; @@ -21,6 +23,9 @@ class _TDFormPageState extends State { /// form 排列方式是否为水平 bool _isFormHorizontal = true; + /// 控制是否进行表单校验 + bool _validateForm = false; + /// 设置按钮是否可点击状态 /// true 表示处于 active 状态 bool horizontalButton = false; @@ -109,51 +114,43 @@ class _TDFormPageState extends State { }, ]; - /// 表单校验规则 - final Map>> _rules = { - 'name': [ - { - 'validator': (String? val) => val != null && val.length == 8, - 'message': '只能输入8个字符英文', - }, - ], - 'password': [ - { - 'validator': (String? val) => val != null && val.length > 6, - 'message': '长度大于6个字符', - }, - ], - 'gender': [ - { - 'validator': (String? val) => val != null && val.isNotEmpty, - 'message': '不能为空', - }, - ], - 'birth': [ - { - 'validator': (String? val) => val != null && val.isNotEmpty, - 'message': '不能为空', - }, - ], - 'place': [ - { - 'validator': (String? val) => val != null && val.isNotEmpty, - 'message': '不能为空', - }, - ], - 'description': [ - { - 'validator': (int? val) => val != null && val > 3, - 'message': '分数过低会影响整体评价', - }, - ], - 'resume': [ - { - 'validator': (String? val) => val != null && val.isNotEmpty, - 'message': '不能为空', - }, - ], - }; + /// 按钮点击事件:改变 _validate 值,从而触发校验 + void _onSubmit() { + setState(() { + _validateForm = true; + }); + } + + /// 定义整个校验规则 + final List _validationRules = [ + TDFormValidation( + validate: (value) => value == null || value.isEmpty ? 'empty' : null, + errorMessage: '输入不能为空', + type: TDFormItemType.input, + ), + TDFormValidation( + validate: (value) => + RegExp(r'^[a-zA-Z]{8}$').hasMatch(value ?? '') ? null : 'invalid', + errorMessage: '只能输入8个字符英文', + type: TDFormItemType.input, + ), + TDFormValidation( + validate: (value) => value == null || value.isEmpty ? 'empty' : null, + errorMessage: '输入不能为空', + type: TDFormItemType.password, + ), + TDFormValidation( + validate: (value) => + RegExp(r'^\d+$').hasMatch(value ?? '') ? null : 'invalid', + errorMessage: '只能输入数字', + type: TDFormItemType.password, + ), + TDFormValidation( + validate: (value) => value == null || value.isEmpty ? 'empty' : null, + errorMessage: '输入不能为空', + type: TDFormItemType.textarea, + ), + ]; @override void initState() { @@ -191,6 +188,8 @@ class _TDFormPageState extends State { return TDForm( disabled: _formDisableState, isHorizontal: _isFormHorizontal, + isValidate: _validateForm, + rules: _validationRules, items: [ TDFormItem( label: '用户名', @@ -397,13 +396,10 @@ class _TDFormPageState extends State { decoration: BoxDecoration( color: theme.whiteColor1, ), - child: const Padding( - padding: EdgeInsets.all(16), + child: Padding( + padding: const EdgeInsets.all(16), child: Row( children: [ - SizedBox( - width: 16, - ), Expanded( child: TDButton( text: '提交', @@ -411,6 +407,7 @@ class _TDFormPageState extends State { type: TDButtonType.fill, theme: TDButtonTheme.primary, shape: TDButtonShape.rectangle, + onTap: _onSubmit, )), ], )), diff --git a/tdesign-component/example/lib/page/td_input_page.dart b/tdesign-component/example/lib/page/td_input_page.dart index 6d85ea198..c55d6b0ea 100644 --- a/tdesign-component/example/lib/page/td_input_page.dart +++ b/tdesign-component/example/lib/page/td_input_page.dart @@ -140,7 +140,7 @@ class _TDInputViewPageState extends State { return Column( children: [ TDInput( - leftLabel: '标签文字123', + leftLabel: '标签文字', required: true, controller: controller[1], backgroundColor: Colors.white, diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index 5f815c17f..11fa015ae 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:tdesign_flutter/src/components/form/td_form_validation.dart'; import 'td_form_inherited.dart'; import '../../../tdesign_flutter.dart'; @@ -17,7 +18,8 @@ class TDForm extends StatefulWidget { this.preventSubmitDefault = true, this.requiredMark = true, // 此处必填项有小问题 this.resetType = 'empty', - this.rules, + required this.rules, + this.isValidate = false, this.scrollToFirstError, this.showErrorMessage = true, this.submitWithWarningMessage = false, @@ -64,8 +66,11 @@ class TDForm extends StatefulWidget { /// 可选项:empty/initial final String? resetType; - /// 表单字段校验规则 - final Object? rules; + /// 整个表单字段校验规则 + final List rules; + + /// 是否对整个 form 进行校验 + final bool isValidate; /// 表单校验不通过时,是否自动滚动到第一个校验不通过的字段,平滑滚动或是瞬间直达。 /// 值为空则表示不滚动。可选项:''/smooth/auto @@ -89,6 +94,8 @@ class _TDFormState extends State { disabled: widget.disabled, labelWidth: widget.labelWidth, isHorizontal: widget.isHorizontal, + isValidate: widget.isValidate, + rules: widget.rules, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: widget.items diff --git a/tdesign-component/lib/src/components/form/td_form_inherited.dart b/tdesign-component/lib/src/components/form/td_form_inherited.dart index 86be39ee9..2af0cec98 100644 --- a/tdesign-component/lib/src/components/form/td_form_inherited.dart +++ b/tdesign-component/lib/src/components/form/td_form_inherited.dart @@ -1,16 +1,23 @@ import 'package:flutter/cupertino.dart'; +import '../../../tdesign_flutter.dart'; + class TDFormInherited extends InheritedWidget { final bool disabled; final double? labelWidth; final bool isHorizontal; + final bool isValidate; + final List rules; - const TDFormInherited({ - required Widget child, - required this.disabled, - required this.isHorizontal, - this.labelWidth, - }) : super(child: child); + const TDFormInherited( + {super.key, + required Widget child, + required this.disabled, + required this.isHorizontal, + required this.isValidate, + this.labelWidth, + required this.rules}) + : super(child: child); static TDFormInherited? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); @@ -20,6 +27,8 @@ class TDFormInherited extends InheritedWidget { bool updateShouldNotify(TDFormInherited oldWidget) { return disabled != oldWidget.disabled || labelWidth != oldWidget.labelWidth || - isHorizontal != oldWidget.isHorizontal; + isHorizontal != oldWidget.isHorizontal || + isValidate != oldWidget.isValidate || + rules != oldWidget.rules; } } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index ca8e68b54..f5d273659 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -2,6 +2,18 @@ import 'package:flutter/material.dart'; import 'td_form_inherited.dart'; import '../../../tdesign_flutter.dart'; +/// 表格单元选用组件类型的枚举 +enum TDFormItemType { + input, + password, + radios, + dateTimePicker, + cascader, + stepper, + rate, + textarea, +} + class TDFormItem extends StatefulWidget { TDFormItem({ required this.type, @@ -12,8 +24,9 @@ class TDFormItem extends StatefulWidget { this.labelAlign, this.labelWidth, this.requiredMark, - this.rules, - this.showErrowMessage, + this.formRules, + this.itemRule, + this.showErrorMessage = true, this.maxLength, this.indicator, this.additionInfo, @@ -51,6 +64,9 @@ class TDFormItem extends StatefulWidget { /// 标签宽度,如果提供则覆盖Form的labelWidth final double? labelWidth; + /// TODO: + /// 竖直状态的两侧 padding + /// Input 控制器 var controller; @@ -67,11 +83,14 @@ class TDFormItem extends StatefulWidget { /// 是否显示必填标记(*) final bool? requiredMark; + /// 整个表单的校验规则 + final List? formRules; + /// 表单项验证规则 - final List? rules; + final List? itemRule; /// 是否显示错误信息 - final bool? showErrowMessage; + final bool showErrorMessage; /// TDTextarea的属性,最大长度 final int? maxLength; @@ -83,37 +102,27 @@ class TDFormItem extends StatefulWidget { _TDFormItemState createState() => _TDFormItemState(); } -/// 表格单元选用组件类型的枚举 -enum TDFormItemType { - input, - password, - radios, - dateTimePicker, - cascader, - stepper, - rate, - textarea, -} - class _TDFormItemState extends State { + /// 从 TDForm 继承获取整个表单的参数 + /// 获取真正的 LabelWidth double get LabelWidth { final inherited = TDFormInherited.of(context); - final double defaultLabelWidth = 8.0; // Default label width + final double defaultLabelWidth = 8.0; - // 优先使用 widget.labelWidth,如果不为空直接返回 + /// 如果 item 传入定制的 labelWidth 则使用 if (widget.labelWidth != null) { return widget.labelWidth as double; } - // 如果 widget.labelWidth 为空,使用 inherited.labelWidth + /// 使用 form 整体传入的 labelWidth if (inherited?.labelWidth != null) { return inherited!.labelWidth as double; } - // 如果两者都为空,返回默认值 return defaultLabelWidth; } + /// 获取 form 是否被禁用的状态 bool get FormState { final inherited = TDFormInherited.of(context); if (inherited?.disabled != null) { @@ -122,6 +131,7 @@ class _TDFormItemState extends State { return false; } + /// 获取 form 是否为水平排列的状态 bool get FormIsHorizontal { final inherited = TDFormInherited.of(context); if (inherited?.isHorizontal != null) { @@ -130,13 +140,54 @@ class _TDFormItemState extends State { return false; } - bool browseOn = false; + /// 获取 form 整体是否校验的信号状态 + bool get FormValidate { + final inherited = TDFormInherited.of(context); + return inherited!.isValidate; + } + + /// 获取整个表单的校验规则 + List get FormRules { + final inherited = TDFormInherited.of(context); + return inherited!.rules; + } + bool browseOn = false; String? _initData; String _selected_1 = ''; + /// 表单 item 的校验错误提示信息 + String? errorMessage; + + // 调用校验方法 + void startValidation() { + setState(() { + errorMessage = validate(); + }); + } + + /// 遍历校验规则并执行 + String? validate() { + String? value = widget.controller?.text; + + for (var rule in FormRules!) { + /// 只对类型匹配的项进行校验 + if (rule.type == widget.type) { + final result = rule.check(value); + if (result != null) { + /// 返回第一个不通过的错误信息 + return result; + } + } + } + return null; + } + @override Widget build(BuildContext context) { + if (FormValidate) { + startValidation(); + } if (FormIsHorizontal) { switch (widget.type) { case TDFormItemType.input: @@ -145,13 +196,23 @@ class _TDFormItemState extends State { hintText: widget.help, contentPadding: EdgeInsets.only(left: LabelWidth), border: InputBorder.none, + errorText: widget.showErrorMessage == true ? errorMessage : null, ), + + /// TODO: + /// 校验失败的提示 icon + // rightBtn: widget.showErrowMessage == true + // ? Icon( + // TDIcons.error_circle_filled, + // color: TDTheme.of(context).fontGyColor3, + // ) + // : null, leftLabel: widget.label, controller: widget.controller, backgroundColor: Colors.white, - // additionInfo: widget.additionInfo, - // additionInfoColor: TDTheme.of(context).errorColor6, + additionInfoColor: TDTheme.of(context).errorColor6, readOnly: FormState, + // required: widget.requiredMark, ); case TDFormItemType.password: return TDInput( @@ -159,6 +220,7 @@ class _TDFormItemState extends State { hintText: widget.help, contentPadding: EdgeInsets.only(left: LabelWidth), border: InputBorder.none, + errorText: widget.showErrorMessage == true ? errorMessage : null, ), type: TDInputType.normal, controller: widget.controller, @@ -191,7 +253,7 @@ class _TDFormItemState extends State { color: theme.whiteColor1, ), child: Padding( - padding: EdgeInsets.all(16), + padding: const EdgeInsets.all(16), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -300,6 +362,11 @@ class _TDFormItemState extends State { maxLength: widget.maxLength, indicator: widget.indicator, readOnly: FormState, + + /// TODO: + /// TDTextarea 目前没用实现提示词 ? 存在调用问题 + additionInfo: widget.showErrorMessage == true ? errorMessage : null, + additionInfoColor: TDTheme.of(context).errorColor6, onChanged: (value) { setState(() {}); }, @@ -312,7 +379,7 @@ class _TDFormItemState extends State { spacer: TDInputSpacer(iconLabelSpace: 0), type: TDInputType.twoLine, inputDecoration: InputDecoration( - contentPadding: EdgeInsets.only(left: 16), + contentPadding: const EdgeInsets.only(left: 16), hintText: widget.help, border: InputBorder.none, ), @@ -331,7 +398,7 @@ class _TDFormItemState extends State { TDInput( inputDecoration: InputDecoration( hintText: widget.help, - contentPadding: EdgeInsets.only(left: 16), + contentPadding: const EdgeInsets.only(left: 16), border: InputBorder.none, ), leftLabelSpace: 16, @@ -459,7 +526,7 @@ class _TDFormItemState extends State { ); case TDFormItemType.rate: return Container( - width: double.infinity, // 设置宽度为无限,横向占满父容器 + width: double.infinity, decoration: BoxDecoration( color: TDTheme.of(context).whiteColor1, ), @@ -491,6 +558,11 @@ class _TDFormItemState extends State { indicator: widget.indicator, readOnly: FormState, layout: TDTextareaLayout.vertical, + + /// TODO: + /// TDTextarea 目前没用实现提示词 ? 存在调用问题 + additionInfo: widget.showErrorMessage == true ? errorMessage : null, + additionInfoColor: TDTheme.of(context).errorColor6, onChanged: (value) { setState(() {}); }, diff --git a/tdesign-component/lib/src/components/form/td_form_validation.dart b/tdesign-component/lib/src/components/form/td_form_validation.dart new file mode 100644 index 000000000..2b5846d56 --- /dev/null +++ b/tdesign-component/lib/src/components/form/td_form_validation.dart @@ -0,0 +1,23 @@ +import '../../../tdesign_flutter.dart'; + +class TDFormValidation { + final String? Function(String?) validate; // 校验方法 + final String errorMessage; + + /// 校验对象的类型 + final TDFormItemType type; + + TDFormValidation({ + required this.validate, + required this.errorMessage, + required this.type, + }); + + // 执行校验逻辑 + String? check(String? value) { + if (validate(value) != null) { + return errorMessage; + } + return null; // 校验通过时返回 null + } +} diff --git a/tdesign-component/lib/tdesign_flutter.dart b/tdesign-component/lib/tdesign_flutter.dart index c2cd74ff7..03ab4d161 100644 --- a/tdesign-component/lib/tdesign_flutter.dart +++ b/tdesign-component/lib/tdesign_flutter.dart @@ -95,4 +95,5 @@ export 'src/theme/td_radius.dart'; export 'src/theme/td_shadows.dart'; export 'src/theme/td_spacers.dart'; export 'src/theme/td_theme.dart'; -export 'src/util/platform_util.dart'; \ No newline at end of file +export 'src/util/platform_util.dart'; +export 'src/components/form/td_form_validation.dart'; From 46a962a1d1bd28f656163889d8af480bf7f155ac Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Fri, 25 Oct 2024 11:02:23 +0800 Subject: [PATCH 20/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=20=E6=80=BB=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=20=E5=8D=95=E4=B8=AA=E8=A1=A8=E6=A0=BC=E5=8D=95?= =?UTF-8?q?=E5=85=83=20=E7=9A=84=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=A1=A8=E5=8D=95=E7=9A=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 78 ++++++++-- .../lib/src/components/form/td_form.dart | 9 +- .../components/form/td_form_inherited.dart | 5 +- .../lib/src/components/form/td_form_item.dart | 136 ++++++++++++++---- .../components/form/td_form_validation.dart | 2 + 5 files changed, 184 insertions(+), 46 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 6b01bb659..b78805680 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -1,8 +1,6 @@ import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; - import '../../annotation/demo.dart'; import '../../base/example_widget.dart'; @@ -14,8 +12,8 @@ class TDFormPage extends StatefulWidget { } class _TDFormPageState extends State { - var controller = []; - String selected_1 = ''; + var _controller = []; + String _selected_1 = ''; /// form 禁用的状态 bool _formDisableState = false; @@ -114,11 +112,24 @@ class _TDFormPageState extends State { }, ]; - /// 按钮点击事件:改变 _validate 值,从而触发校验 - void _onSubmit() { - setState(() { - _validateForm = true; - }); + /// TDDateTimePicker 监控数据 + void _dateONChange(newValue) { + print('Date value changed to $newValue'); + } + + /// TDCasader 监控数据 + void _localONChange(newValue) { + print('Local value changed to $newValue'); + } + + /// TDStepper 监控数据 + void _stepperONChange(newValue) { + print('Stepper value changed to $newValue'); + } + + /// TDRate 监控数据 + void _rateONChange(newValue) { + print('Rate value changed to $newValue'); } /// 定义整个校验规则 @@ -155,11 +166,25 @@ class _TDFormPageState extends State { @override void initState() { for (var i = 0; i < 3; i++) { - controller.add(TextEditingController()); + _controller.add(TextEditingController()); } super.initState(); } + /// 提交按钮钮点击事件: + /// 改变 _validate 值,从而触发校验 + /// 获取表单的数据 + void _onSubmit() { + setState(() { + _validateForm = true; + print('input1@ ${_controller[0]}'); + print('input2@ ${_controller[1]}'); + print('input3@ ${_controller[2]}'); + + /// 其他通过回调获取数据 + }); + } + @override Widget build(BuildContext context) { return ExamplePage( @@ -190,6 +215,9 @@ class _TDFormPageState extends State { isHorizontal: _isFormHorizontal, isValidate: _validateForm, rules: _validationRules, + + /// 确定整个表单是否展示提示信息 + formShowErrorMessage: true, items: [ TDFormItem( label: '用户名', @@ -197,7 +225,10 @@ class _TDFormPageState extends State { help: '请输入用户名', // additionInfo: '只能输入8个字符英文', labelWidth: 43.0, - controller: controller[0], + controller: _controller[0], + + /// 控制单个 item 是否展示错误提醒 + showErrorMessage: false, // requiredMark: true, ), TDFormItem( @@ -206,7 +237,7 @@ class _TDFormPageState extends State { help: '请输入密码', // additionInfo: '只能输入数字', labelWidth: 60.0, - controller: controller[1], + controller: _controller[1], ), TDFormItem( label: '性别', @@ -221,7 +252,11 @@ class _TDFormPageState extends State { type: TDFormItemType.dateTimePicker, /// 引入需要的日期数据 - select: selected_1, + select: _selected_1, + onChange: _dateONChange, + + ///对于复杂表单项可以自定义传入校验方法 + //itemRule: , ), TDFormItem( label: '籍贯', @@ -229,22 +264,37 @@ class _TDFormPageState extends State { /// 引入需要的地点数据 localData: _data, + onChange: _localONChange, + + ///对于复杂表单项可以自定义传入校验方法 + //itemRule: , ), TDFormItem( label: '年限', type: TDFormItemType.stepper, /// 为 TDStepper 预留其他设置 + onChange: _stepperONChange, + + ///对于复杂表单项可以自定义传入校验方法 + //itemRule: , ), TDFormItem( label: '自我评价', type: TDFormItemType.rate, + allowHalf: true, + rateCount: 5, + rateValue: 3, + onChange: _rateONChange, + + ///对于复杂表单项可以自定义传入校验方法 + //itemRule: , ), TDFormItem( label: '个人简介', type: TDFormItemType.textarea, help: '请输入个人简介', - controller: controller[2], + controller: _controller[2], /// 为 TDTextarea 长文本其他参数做预留 API maxLength: 500, diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index 11fa015ae..67c4c93f5 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -7,6 +7,7 @@ class TDForm extends StatefulWidget { const TDForm({ Key? key, required this.items, + required this.rules, this.colon = false, this.contentAlign = 'left', this.data, @@ -18,10 +19,9 @@ class TDForm extends StatefulWidget { this.preventSubmitDefault = true, this.requiredMark = true, // 此处必填项有小问题 this.resetType = 'empty', - required this.rules, this.isValidate = false, this.scrollToFirstError, - this.showErrorMessage = true, + this.formShowErrorMessage = true, this.submitWithWarningMessage = false, }) : super(key: key); @@ -35,7 +35,7 @@ class TDForm extends StatefulWidget { /// 可选项: left/right final String? contentAlign; - /// 表单数据 + /// TODO: 整个表单数据 是否需要将所有 items 的数据整合输出? final Object? data; /// 表单排列方式是否为 水平方向 @@ -78,7 +78,7 @@ class TDForm extends StatefulWidget { /// 校验不通过时,是否显示错误提示信息,统一控制全部表单项 /// 如果希望控制单个表单项,请给 FormItem 设置该属性 - final bool? showErrorMessage; + final bool? formShowErrorMessage; /// 【讨论中】当校验结果只有告警信息时,是否触发 submit 提交事件 final bool? submitWithWarningMessage; @@ -96,6 +96,7 @@ class _TDFormState extends State { isHorizontal: widget.isHorizontal, isValidate: widget.isValidate, rules: widget.rules, + formShowErrorMessage: widget.formShowErrorMessage, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: widget.items diff --git a/tdesign-component/lib/src/components/form/td_form_inherited.dart b/tdesign-component/lib/src/components/form/td_form_inherited.dart index 2af0cec98..f98410fbe 100644 --- a/tdesign-component/lib/src/components/form/td_form_inherited.dart +++ b/tdesign-component/lib/src/components/form/td_form_inherited.dart @@ -8,6 +8,7 @@ class TDFormInherited extends InheritedWidget { final bool isHorizontal; final bool isValidate; final List rules; + final bool? formShowErrorMessage; const TDFormInherited( {super.key, @@ -16,6 +17,7 @@ class TDFormInherited extends InheritedWidget { required this.isHorizontal, required this.isValidate, this.labelWidth, + this.formShowErrorMessage, required this.rules}) : super(child: child); @@ -29,6 +31,7 @@ class TDFormInherited extends InheritedWidget { labelWidth != oldWidget.labelWidth || isHorizontal != oldWidget.isHorizontal || isValidate != oldWidget.isValidate || - rules != oldWidget.rules; + rules != oldWidget.rules || + formShowErrorMessage != oldWidget.formShowErrorMessage; } } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index f5d273659..459fe2b7e 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -26,9 +26,14 @@ class TDFormItem extends StatefulWidget { this.requiredMark, this.formRules, this.itemRule, + this.onChange, this.showErrorMessage = true, this.maxLength, this.indicator, + this.allowHalf = false, + this.rateValue = 3, + this.rateCount = 5, + this.rateGap, this.additionInfo, this.controller, this.select = '', @@ -48,7 +53,7 @@ class TDFormItem extends StatefulWidget { /// 表单内容对齐方式:'left' 或 'right' final String? contentAlign; - /// TODO: + /// TODO:右箭头 API 未实现 /// 是否显示右侧箭头 final bool? arrow; @@ -64,8 +69,9 @@ class TDFormItem extends StatefulWidget { /// 标签宽度,如果提供则覆盖Form的labelWidth final double? labelWidth; - /// TODO: - /// 竖直状态的两侧 padding + /// TODO: 竖直状态的左侧对齐 padding + /// 目前部分组件需要完善 + /// 左侧 起始的 padding 位置不同 /// Input 控制器 var controller; @@ -89,15 +95,31 @@ class TDFormItem extends StatefulWidget { /// 表单项验证规则 final List? itemRule; + /// 表单 item 的回调函数 + final ValueChanged? onChange; + /// 是否显示错误信息 final bool showErrorMessage; - /// TDTextarea的属性,最大长度 + /// TDTextarea 的属性,最大长度 final int? maxLength; - /// TDTextarea的属性,指示器 + /// TDTextarea 的属性,指示器 final bool? indicator; + /// TDRate 属性,是否开启可选半个等级 + final bool allowHalf; + + /// TDRate 属性,评分的满分数 + final int rateCount; + + /// TDRate 属性,初始时的 value + final double rateValue; + + /// TDRate 属性 + /// 评分图标的间距,默认:TDTheme.of(context).spacer8 + final double? rateGap; + @override _TDFormItemState createState() => _TDFormItemState(); } @@ -146,6 +168,16 @@ class _TDFormItemState extends State { return inherited!.isValidate; } + /// 获取整个表格是否需要展示错误提示 + bool? get ShowErrorMessage { + final inherited = TDFormInherited.of(context); + if (widget.showErrorMessage != null) { + return widget.showErrorMessage; + } else { + return inherited!.formShowErrorMessage; + } + } + /// 获取整个表单的校验规则 List get FormRules { final inherited = TDFormInherited.of(context); @@ -159,7 +191,9 @@ class _TDFormItemState extends State { /// 表单 item 的校验错误提示信息 String? errorMessage; - // 调用校验方法 + double rate = 0; + + /// 调用校验方法 void startValidation() { setState(() { errorMessage = validate(); @@ -196,11 +230,10 @@ class _TDFormItemState extends State { hintText: widget.help, contentPadding: EdgeInsets.only(left: LabelWidth), border: InputBorder.none, - errorText: widget.showErrorMessage == true ? errorMessage : null, + errorText: ShowErrorMessage == true ? errorMessage : null, ), - /// TODO: - /// 校验失败的提示 icon + /// TODO: Input 校验失败时的提示 icon // rightBtn: widget.showErrowMessage == true // ? Icon( // TDIcons.error_circle_filled, @@ -212,6 +245,8 @@ class _TDFormItemState extends State { backgroundColor: Colors.white, additionInfoColor: TDTheme.of(context).errorColor6, readOnly: FormState, + + /// TODO: requiredMark 会使得间距变大 要调整 // required: widget.requiredMark, ); case TDFormItemType.password: @@ -220,7 +255,7 @@ class _TDFormItemState extends State { hintText: widget.help, contentPadding: EdgeInsets.only(left: LabelWidth), border: InputBorder.none, - errorText: widget.showErrorMessage == true ? errorMessage : null, + errorText: ShowErrorMessage == true ? errorMessage : null, ), type: TDInputType.normal, controller: widget.controller, @@ -275,6 +310,13 @@ class _TDFormItemState extends State { enable: !FormState, ); }).toList(), + + /// TODO: TDRadioGroup 回调函数存在覆盖问题 + // onRadioGroupChange: (ids) { + // setState(() { + // print(ids); + // }); + // }, ), ), ], @@ -289,6 +331,9 @@ class _TDFormItemState extends State { setState(() { widget.select = '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + if (widget.onChange != null) { + widget.onChange!(widget.select); + } }); Navigator.of(context).pop(); }, @@ -315,6 +360,9 @@ class _TDFormItemState extends State { result.add(element.label); }); _selected_1 = result.join('/'); + if (widget.onChange != null) { + widget.onChange!(_selected_1); + } }); }, onClose: () { Navigator.of(context).pop(); @@ -340,6 +388,13 @@ class _TDFormItemState extends State { TDStepper( theme: TDStepperTheme.filled, disabled: FormState, + onChange: (value) { + setState(() { + if (widget.onChange != null) { + widget.onChange!(value); + } + }); + }, ), ], ), @@ -349,9 +404,20 @@ class _TDFormItemState extends State { return TDCell( title: widget.label, noteWidget: TDRate( - value: 3, - allowHalf: true, + count: widget.rateCount, + value: widget.rateValue, + allowHalf: widget.allowHalf, disabled: FormState, + onChange: (value) { + setState(() { + if (widget.onChange != null) { + widget.onChange!(value); + } + }); + + /// TODO: Rated 组件的校验 + // if (rate < 3) {} + }, )); case TDFormItemType.textarea: return TDTextarea( @@ -362,14 +428,8 @@ class _TDFormItemState extends State { maxLength: widget.maxLength, indicator: widget.indicator, readOnly: FormState, - - /// TODO: - /// TDTextarea 目前没用实现提示词 ? 存在调用问题 - additionInfo: widget.showErrorMessage == true ? errorMessage : null, + additionInfo: ShowErrorMessage == true ? errorMessage : null, additionInfoColor: TDTheme.of(context).errorColor6, - onChanged: (value) { - setState(() {}); - }, ); } } else { @@ -455,6 +515,10 @@ class _TDFormItemState extends State { enable: !FormState, ); }).toList(), + // onRadioGroupChange: (value) { + // setState(() { + // }); + // }, ), ], ), @@ -468,6 +532,9 @@ class _TDFormItemState extends State { setState(() { widget.select = '${selected['year'].toString().padLeft(4, '0')}-${selected['month'].toString().padLeft(2, '0')}-${selected['day'].toString().padLeft(2, '0')}'; + if (widget.onChange != null) { + widget.onChange!(widget.select); + } }); Navigator.of(context).pop(); }, @@ -494,6 +561,9 @@ class _TDFormItemState extends State { result.add(element.label); }); _selected_1 = result.join('/'); + if (widget.onChange != null) { + widget.onChange!(_selected_1); + } }); }, onClose: () { Navigator.of(context).pop(); @@ -519,6 +589,13 @@ class _TDFormItemState extends State { TDStepper( theme: TDStepperTheme.filled, disabled: FormState, + onChange: (value) { + setState(() { + if (widget.onChange != null) { + widget.onChange!(value); + } + }); + }, ), ], ), @@ -541,10 +618,17 @@ class _TDFormItemState extends State { ), const SizedBox(height: 8), TDRate( - value: 3, - allowHalf: true, - disabled: FormState, - ), + count: widget.rateCount, + value: widget.rateValue, + allowHalf: widget.allowHalf, + disabled: FormState, + onChange: (value) { + setState(() { + if (widget.onChange != null) { + widget.onChange!(value); + } + }); + }), ], ), )); @@ -558,10 +642,7 @@ class _TDFormItemState extends State { indicator: widget.indicator, readOnly: FormState, layout: TDTextareaLayout.vertical, - - /// TODO: - /// TDTextarea 目前没用实现提示词 ? 存在调用问题 - additionInfo: widget.showErrorMessage == true ? errorMessage : null, + additionInfo: ShowErrorMessage == true ? errorMessage : null, additionInfoColor: TDTheme.of(context).errorColor6, onChanged: (value) { setState(() {}); @@ -646,6 +727,7 @@ class _TDFormItemState extends State { children: [ Expanded( child: TDText( + textAlign: TextAlign.right, output, font: TDTheme.of(context).fontBodyLarge, textColor: diff --git a/tdesign-component/lib/src/components/form/td_form_validation.dart b/tdesign-component/lib/src/components/form/td_form_validation.dart index 2b5846d56..4de3587ae 100644 --- a/tdesign-component/lib/src/components/form/td_form_validation.dart +++ b/tdesign-component/lib/src/components/form/td_form_validation.dart @@ -1,5 +1,7 @@ import '../../../tdesign_flutter.dart'; +/// 实现普通表单项的校验 +/// 校验规则 和 错误提醒 class TDFormValidation { final String? Function(String?) validate; // 校验方法 final String errorMessage; From e36251379b9697b9b5d7fae7fd8670e8852ff17e Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Fri, 25 Oct 2024 11:05:42 +0800 Subject: [PATCH 21/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=20TDFormItem=20?= =?UTF-8?q?=E9=92=88=E5=AF=B9=20Rate=20RadioGroup=20=E7=AD=89=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=AE=9A=E5=88=B6=20API=20=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tdesign-component/example/lib/page/td_form_page.dart | 1 + tdesign-component/lib/src/components/form/td_form_item.dart | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index b78805680..deef56eb0 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -246,6 +246,7 @@ class _TDFormPageState extends State { /// 扩展一下数量和选项内容 radios: _radios, + // radioGroupSpacing: , ), TDFormItem( label: '生日', diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 459fe2b7e..3fe90be31 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -30,6 +30,7 @@ class TDFormItem extends StatefulWidget { this.showErrorMessage = true, this.maxLength, this.indicator, + this.radioGroupSpacing, this.allowHalf = false, this.rateValue = 3, this.rateCount = 5, @@ -107,6 +108,9 @@ class TDFormItem extends StatefulWidget { /// TDTextarea 的属性,指示器 final bool? indicator; + /// TDRadioGroup 属性,文字与单选框的间距 + final double? radioGroupSpacing; + /// TDRate 属性,是否开启可选半个等级 final bool allowHalf; @@ -299,6 +303,7 @@ class _TDFormItemState extends State { SizedBox(width: LabelWidth), Expanded( child: TDRadioGroup( + // spacing: widget.radioGroupSpacing, selectId: 'index:1', direction: Axis.horizontal, directionalTdRadios: widget.radios.entries.map((entry) { From c3118e51e044490a2df765bdf739b0a249b79a74 Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 28 Oct 2024 00:26:37 +0800 Subject: [PATCH 22/25] =?UTF-8?q?TDForm=20=E6=95=B4=E4=BD=93=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20=E5=AE=9E=E7=8E=B0=E5=8D=95=E4=B8=AA=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E5=8D=95=E5=85=83=E7=9A=84=E6=95=B0=E6=8D=AE=E7=9B=91?= =?UTF-8?q?=E5=90=AC=20=E5=AE=9E=E7=8E=B0=E6=95=B4=E4=B8=AA=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=95=B0=E6=8D=AE=E7=9A=84=E6=8F=90=E4=BA=A4=20TODO:?= =?UTF-8?q?=20=E6=9E=84=E5=BB=BA=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=81=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 34 +++-- .../lib/src/components/form/td_form.dart | 19 ++- .../components/form/td_form_inherited.dart | 25 ++-- .../lib/src/components/form/td_form_item.dart | 120 +++++++----------- 4 files changed, 93 insertions(+), 105 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index deef56eb0..5c463c55b 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -112,24 +112,40 @@ class _TDFormPageState extends State { }, ]; + List _formData = []; // 存储所有 FormItem 数据的列表 + + void _updateFormData(String label, dynamic value) { + final existingIndex = + _formData.indexWhere((element) => element['label'] == label); + if (existingIndex != -1) { + _formData[existingIndex]['value'] = value; // 更新现有项 + } else { + _formData.add({'label': label, 'value': value}); // 添加新项 + } + } + /// TDDateTimePicker 监控数据 void _dateONChange(newValue) { print('Date value changed to $newValue'); + _updateFormData('Date', newValue); // 添加到 formData } /// TDCasader 监控数据 void _localONChange(newValue) { print('Local value changed to $newValue'); + _updateFormData('Casader', newValue); } /// TDStepper 监控数据 void _stepperONChange(newValue) { print('Stepper value changed to $newValue'); + _updateFormData('Stepper', newValue); // 添加到 formData } /// TDRate 监控数据 void _rateONChange(newValue) { print('Rate value changed to $newValue'); + _updateFormData('Rate', newValue); // 添加到 formData } /// 定义整个校验规则 @@ -165,6 +181,7 @@ class _TDFormPageState extends State { @override void initState() { + /// 三个文本型的表格单元 for (var i = 0; i < 3; i++) { _controller.add(TextEditingController()); } @@ -177,11 +194,12 @@ class _TDFormPageState extends State { void _onSubmit() { setState(() { _validateForm = true; - print('input1@ ${_controller[0]}'); - print('input2@ ${_controller[1]}'); - print('input3@ ${_controller[2]}'); + for (var i = 0; i < 3; i++) { + _updateFormData('input${i}', _controller[i].text); + } /// 其他通过回调获取数据 + print('Form Data: $_formData'); // 输出所有回调获取的数据 }); } @@ -215,6 +233,7 @@ class _TDFormPageState extends State { isHorizontal: _isFormHorizontal, isValidate: _validateForm, rules: _validationRules, + formContentAlign: TextAlign.left, /// 确定整个表单是否展示提示信息 formShowErrorMessage: true, @@ -223,19 +242,17 @@ class _TDFormPageState extends State { label: '用户名', type: TDFormItemType.input, help: '请输入用户名', - // additionInfo: '只能输入8个字符英文', labelWidth: 43.0, controller: _controller[0], /// 控制单个 item 是否展示错误提醒 - showErrorMessage: false, + showErrorMessage: true, // requiredMark: true, ), TDFormItem( label: '密码', type: TDFormItemType.password, help: '请输入密码', - // additionInfo: '只能输入数字', labelWidth: 60.0, controller: _controller[1], ), @@ -254,7 +271,7 @@ class _TDFormPageState extends State { /// 引入需要的日期数据 select: _selected_1, - onChange: _dateONChange, + // onChange: _dateONChange, ///对于复杂表单项可以自定义传入校验方法 //itemRule: , @@ -472,9 +489,6 @@ class _TDFormPageState extends State { padding: EdgeInsets.all(16), child: Row( children: [ - SizedBox( - width: 16, - ), Expanded( child: TDButton( text: '提交', diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index 67c4c93f5..00a3182cb 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -9,12 +9,12 @@ class TDForm extends StatefulWidget { required this.items, required this.rules, this.colon = false, - this.contentAlign = 'left', + this.formContentAlign = TextAlign.left, this.data, this.isHorizontal = true, this.disabled = false, this.errorMessage, - this.labelAlign = 'right', + this.formLabelAlign = TextAlign.left, this.labelWidth = 20.0, this.preventSubmitDefault = true, this.requiredMark = true, // 此处必填项有小问题 @@ -31,12 +31,15 @@ class TDForm extends StatefulWidget { /// 是否在表单标签字段右侧显示冒号 final bool? colon; - /// 表单内容对齐方式: 左对齐、右对齐 - /// 可选项: left/right - final String? contentAlign; + /// 表单内容对齐方式: 左对齐、右对齐、居中对齐 + /// 可选项: left/right/center + /// 默认为左对齐 + /// 优先级低于 TDFormItem 的对齐 API + /// TODO: TDStepper TDRate 等组件没用实现通用性 + final TextAlign formContentAlign; /// TODO: 整个表单数据 是否需要将所有 items 的数据整合输出? - final Object? data; + final List? data; /// 表单排列方式是否为 水平方向 final bool isHorizontal; @@ -50,7 +53,8 @@ class TDForm extends StatefulWidget { /// 表单字段标签的对齐方式: /// 左对齐、右对齐、顶部对齐 /// 可选项: left/right/top - final String? labelAlign; + /// TODO: 表单总体标签对齐方式 + final TextAlign? formLabelAlign; /// 可以整体设置 label 标签宽度 final double? labelWidth; @@ -96,6 +100,7 @@ class _TDFormState extends State { isHorizontal: widget.isHorizontal, isValidate: widget.isValidate, rules: widget.rules, + formContentAlign: widget.formContentAlign, formShowErrorMessage: widget.formShowErrorMessage, child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/tdesign-component/lib/src/components/form/td_form_inherited.dart b/tdesign-component/lib/src/components/form/td_form_inherited.dart index f98410fbe..e58d79565 100644 --- a/tdesign-component/lib/src/components/form/td_form_inherited.dart +++ b/tdesign-component/lib/src/components/form/td_form_inherited.dart @@ -9,17 +9,19 @@ class TDFormInherited extends InheritedWidget { final bool isValidate; final List rules; final bool? formShowErrorMessage; + final TextAlign formContentAlign; - const TDFormInherited( - {super.key, - required Widget child, - required this.disabled, - required this.isHorizontal, - required this.isValidate, - this.labelWidth, - this.formShowErrorMessage, - required this.rules}) - : super(child: child); + const TDFormInherited({ + super.key, + required Widget child, + required this.disabled, + required this.isHorizontal, + required this.isValidate, + required this.rules, + required this.formContentAlign, + this.labelWidth, + this.formShowErrorMessage, + }) : super(child: child); static TDFormInherited? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); @@ -32,6 +34,7 @@ class TDFormInherited extends InheritedWidget { isHorizontal != oldWidget.isHorizontal || isValidate != oldWidget.isValidate || rules != oldWidget.rules || - formShowErrorMessage != oldWidget.formShowErrorMessage; + formShowErrorMessage != oldWidget.formShowErrorMessage || + formContentAlign != oldWidget.formContentAlign; } } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index 3fe90be31..f0cc1667b 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -18,10 +18,9 @@ class TDFormItem extends StatefulWidget { TDFormItem({ required this.type, this.label, - this.arrow = false, - this.contentAlign = 'left', this.help, this.labelAlign, + this.contentAlign, this.labelWidth, this.requiredMark, this.formRules, @@ -51,27 +50,25 @@ class TDFormItem extends StatefulWidget { /// 表格单元需要使用的组件类型 final TDFormItemType type; - /// 表单内容对齐方式:'left' 或 'right' - final String? contentAlign; - - /// TODO:右箭头 API 未实现 - /// 是否显示右侧箭头 - final bool? arrow; - /// TDInput的辅助信息 final String? additionInfo; /// TDInput 默认显示文字 final String? help; - /// 标签对齐方式:'left', 'right', 或 'top' - final String? labelAlign; + /// TODO: item 标签对齐方式 + /// 可选: left、right、top + final TextAlign? labelAlign; + + /// 表单显示内容对齐方式: + /// left、right、top + /// TODO: TDStepper TDRate 等组件没用实现通用性 + final TextAlign? contentAlign; /// 标签宽度,如果提供则覆盖Form的labelWidth final double? labelWidth; - /// TODO: 竖直状态的左侧对齐 padding - /// 目前部分组件需要完善 + /// TODO: 竖直状态的左侧对齐 padding 需要目前部分组件的更新支持 /// 左侧 起始的 padding 位置不同 /// Input 控制器 @@ -133,7 +130,7 @@ class _TDFormItemState extends State { /// 获取真正的 LabelWidth double get LabelWidth { final inherited = TDFormInherited.of(context); - final double defaultLabelWidth = 8.0; + final defaultLabelWidth = 8.0; /// 如果 item 传入定制的 labelWidth 则使用 if (widget.labelWidth != null) { @@ -157,6 +154,18 @@ class _TDFormItemState extends State { return false; } + /// 获取 form 以及 formItem 的内容排列方式 + TextAlign get FormContentAlign { + final inherited = TDFormInherited.of(context); + if (widget.contentAlign != null) { + /// 断言 widget.contentAlign 不会为空 + return widget.contentAlign!; + } + + /// 如果 没用为 item 定制内容排列方式 则全部使用总表单的内容排列方式 + return inherited!.formContentAlign; + } + /// 获取 form 是否为水平排列的状态 bool get FormIsHorizontal { final inherited = TDFormInherited.of(context); @@ -197,6 +206,14 @@ class _TDFormItemState extends State { double rate = 0; + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (FormValidate) { + startValidation(); + } + } + /// 调用校验方法 void startValidation() { setState(() { @@ -223,16 +240,14 @@ class _TDFormItemState extends State { @override Widget build(BuildContext context) { - if (FormValidate) { - startValidation(); - } if (FormIsHorizontal) { switch (widget.type) { case TDFormItemType.input: return TDInput( inputDecoration: InputDecoration( hintText: widget.help, - contentPadding: EdgeInsets.only(left: LabelWidth), + contentPadding: EdgeInsets.only( + left: FormContentAlign == TextAlign.center ? 0 : LabelWidth), border: InputBorder.none, errorText: ShowErrorMessage == true ? errorMessage : null, ), @@ -244,13 +259,14 @@ class _TDFormItemState extends State { // color: TDTheme.of(context).fontGyColor3, // ) // : null, + contentAlignment: FormContentAlign, leftLabel: widget.label, controller: widget.controller, backgroundColor: Colors.white, additionInfoColor: TDTheme.of(context).errorColor6, readOnly: FormState, - /// TODO: requiredMark 会使得间距变大 要调整 + /// TODO: requiredMark 会使得间距变大 要适应优化 // required: widget.requiredMark, ); case TDFormItemType.password: @@ -261,6 +277,7 @@ class _TDFormItemState extends State { border: InputBorder.none, errorText: ShowErrorMessage == true ? errorMessage : null, ), + contentAlignment: FormContentAlign, type: TDInputType.normal, controller: widget.controller, obscureText: !browseOn, @@ -346,7 +363,7 @@ class _TDFormItemState extends State { dateEnd: [2023, 12, 31], initialDate: [2012, 1, 1]); }, - child: buildSelectRow(context, widget.select, '选择时间'), + child: _buildSelectRow(context, widget.select, '选择时间'), ); case TDFormItemType.cascader: return GestureDetector( @@ -358,8 +375,8 @@ class _TDFormItemState extends State { theme: 'step', onChange: (List selectData) { setState(() { - List result = []; - int len = selectData.length; + var result = []; + var len = selectData.length; _initData = selectData[len - 1].value!; selectData.forEach((element) { result.add(element.label); @@ -547,7 +564,7 @@ class _TDFormItemState extends State { dateEnd: [2023, 12, 31], initialDate: [2012, 1, 1]); }, - child: buildSelectRow(context, widget.select, '选择时间'), + child: _buildSelectRow(context, widget.select, '选择时间'), ); case TDFormItemType.cascader: return GestureDetector( @@ -559,8 +576,8 @@ class _TDFormItemState extends State { theme: 'step', onChange: (List selectData) { setState(() { - List result = []; - int len = selectData.length; + var result = []; + var len = selectData.length; _initData = selectData[len - 1].value!; selectData.forEach((element) { result.add(element.label); @@ -655,58 +672,6 @@ class _TDFormItemState extends State { ); } } - - /// TODO: 构建错误的提示页面 - } - - Widget buildSelectRow(BuildContext context, String output, String title) { - return Container( - color: TDTheme.of(context).whiteColor1, - height: 56, - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16, top: 16, bottom: 16), - child: TDText( - title, - font: TDTheme.of(context).fontBodyLarge, - ), - ), - Padding( - padding: const EdgeInsets.only(right: 16), - child: Row( - children: [ - TDText( - output, - font: TDTheme.of(context).fontBodyLarge, - textColor: - TDTheme.of(context).fontGyColor3.withOpacity(0.4), - ), - Padding( - padding: const EdgeInsets.only(left: 2), - child: Icon( - TDIcons.chevron_right, - color: - TDTheme.of(context).fontGyColor3.withOpacity(0.4), - ), - ), - ], - ), - ), - ], - ), - const TDDivider( - margin: EdgeInsets.only( - left: 16, - ), - ) - ], - ), - ); } Widget _buildSelectRow(BuildContext context, String output, String title) { @@ -732,6 +697,7 @@ class _TDFormItemState extends State { children: [ Expanded( child: TDText( + /// TODO: 选择器 结果展示部分 也可以单独设 API textAlign: TextAlign.right, output, font: TDTheme.of(context).fontBodyLarge, From 7412883f3a2fd53c3fdad1107377f9c1a8e392de Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 28 Oct 2024 09:20:04 +0800 Subject: [PATCH 23/25] =?UTF-8?q?=E9=87=87=E7=94=A8=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E5=92=8C=E9=A2=84=E5=8A=A0=E8=BD=BD=E4=BC=98=E5=8C=96=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9E=84=E5=BB=BA=E6=80=A7=E8=83=BD=20TODO=EF=BC=9A?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/lib/page/td_form_page.dart | 84 +++++++++++-------- .../lib/src/components/form/td_form.dart | 31 +++---- .../lib/src/components/form/td_form_item.dart | 5 +- 3 files changed, 67 insertions(+), 53 deletions(-) diff --git a/tdesign-component/example/lib/page/td_form_page.dart b/tdesign-component/example/lib/page/td_form_page.dart index 5c463c55b..58e1fea63 100644 --- a/tdesign-component/example/lib/page/td_form_page.dart +++ b/tdesign-component/example/lib/page/td_form_page.dart @@ -112,40 +112,76 @@ class _TDFormPageState extends State { }, ]; - List _formData = []; // 存储所有 FormItem 数据的列表 + /// 整个表单存放的数据 + List _formData = []; - void _updateFormData(String label, dynamic value) { - final existingIndex = - _formData.indexWhere((element) => element['label'] == label); + void _updateFormData( + + /// type: 表格单元类型 num: 重复的类型的表格单元的序号 value:表格单元存放的数据 + {required TDFormItemType type, + int num = 0, + required value}) { + final existingIndex = _formData.indexWhere( + (element) => element['itemType'] == type && element['num'] == num, + ); if (existingIndex != -1) { - _formData[existingIndex]['value'] = value; // 更新现有项 + _formData[existingIndex]['value'] = value; } else { - _formData.add({'label': label, 'value': value}); // 添加新项 + _formData.add({'itemType': type, 'num': num, 'value': value}); } } /// TDDateTimePicker 监控数据 void _dateONChange(newValue) { print('Date value changed to $newValue'); - _updateFormData('Date', newValue); // 添加到 formData + _updateFormData( + type: TDFormItemType.dateTimePicker, value: newValue); // 添加到 formData } /// TDCasader 监控数据 void _localONChange(newValue) { print('Local value changed to $newValue'); - _updateFormData('Casader', newValue); + _updateFormData(type: TDFormItemType.cascader, value: newValue); } /// TDStepper 监控数据 void _stepperONChange(newValue) { print('Stepper value changed to $newValue'); - _updateFormData('Stepper', newValue); // 添加到 formData + _updateFormData( + type: TDFormItemType.stepper, value: newValue); // 添加到 formData } /// TDRate 监控数据 void _rateONChange(newValue) { print('Rate value changed to $newValue'); - _updateFormData('Rate', newValue); // 添加到 formData + _updateFormData(type: TDFormItemType.rate, value: newValue); // 添加到 formData + } + + @override + void initState() { + /// 三个文本型的表格单元 + for (var i = 0; i < 3; i++) { + _controller.add(TextEditingController()); + } + super.initState(); + } + + /// 提交按钮钮点击事件: + /// 改变 _validate 值,从而触发校验 + /// 获取表单的数据 + void _onSubmit() { + setState(() { + _validateForm = true; + for (var i = 0; i < 3; i++) { + _updateFormData( + type: TDFormItemType.input, + num: (i + 1), + value: _controller[i].text); + } + + /// 其他通过回调获取数据 + print('Form Data: $_formData'); + }); } /// 定义整个校验规则 @@ -179,30 +215,6 @@ class _TDFormPageState extends State { ), ]; - @override - void initState() { - /// 三个文本型的表格单元 - for (var i = 0; i < 3; i++) { - _controller.add(TextEditingController()); - } - super.initState(); - } - - /// 提交按钮钮点击事件: - /// 改变 _validate 值,从而触发校验 - /// 获取表单的数据 - void _onSubmit() { - setState(() { - _validateForm = true; - for (var i = 0; i < 3; i++) { - _updateFormData('input${i}', _controller[i].text); - } - - /// 其他通过回调获取数据 - print('Form Data: $_formData'); // 输出所有回调获取的数据 - }); - } - @override Widget build(BuildContext context) { return ExamplePage( @@ -268,10 +280,11 @@ class _TDFormPageState extends State { TDFormItem( label: '生日', type: TDFormItemType.dateTimePicker, + contentAlign: TextAlign.right, /// 引入需要的日期数据 select: _selected_1, - // onChange: _dateONChange, + onChange: _dateONChange, ///对于复杂表单项可以自定义传入校验方法 //itemRule: , @@ -279,6 +292,7 @@ class _TDFormPageState extends State { TDFormItem( label: '籍贯', type: TDFormItemType.cascader, + contentAlign: TextAlign.right, /// 引入需要的地点数据 localData: _data, diff --git a/tdesign-component/lib/src/components/form/td_form.dart b/tdesign-component/lib/src/components/form/td_form.dart index 00a3182cb..c5cb13a8c 100644 --- a/tdesign-component/lib/src/components/form/td_form.dart +++ b/tdesign-component/lib/src/components/form/td_form.dart @@ -18,7 +18,6 @@ class TDForm extends StatefulWidget { this.labelWidth = 20.0, this.preventSubmitDefault = true, this.requiredMark = true, // 此处必填项有小问题 - this.resetType = 'empty', this.isValidate = false, this.scrollToFirstError, this.formShowErrorMessage = true, @@ -66,14 +65,11 @@ class TDForm extends StatefulWidget { /// 是否显示必填符号(*),默认显示 final bool? requiredMark; - /// 重置表单的方式,值为 empty 表示重置表单为空,值为 initial 表示重置表单数据为初始值 - /// 可选项:empty/initial - final String? resetType; - /// 整个表单字段校验规则 final List rules; /// 是否对整个 form 进行校验 + /// TODO: 无法重复点击提交按钮的校验进行重复校验 final bool isValidate; /// 表单校验不通过时,是否自动滚动到第一个校验不通过的字段,平滑滚动或是瞬间直达。 @@ -92,6 +88,15 @@ class TDForm extends StatefulWidget { } class _TDFormState extends State { + late final List _formItems; + + @override + void initState() { + super.initState(); + _formItems = + widget.items.expand((item) => [item, SizedBox(height: 1)]).toList(); + } + @override Widget build(BuildContext context) { return TDFormInherited( @@ -102,16 +107,12 @@ class _TDFormState extends State { rules: widget.rules, formContentAlign: widget.formContentAlign, formShowErrorMessage: widget.formShowErrorMessage, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: widget.items - .map((item) => Column( - children: [ - item, - SizedBox(height: 1), - ], - )) - .toList(), + child: ListView.builder( + itemCount: _formItems.length, + itemBuilder: (context, index) => _formItems[index], + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + cacheExtent: 500, ), ); } diff --git a/tdesign-component/lib/src/components/form/td_form_item.dart b/tdesign-component/lib/src/components/form/td_form_item.dart index f0cc1667b..87486868a 100644 --- a/tdesign-component/lib/src/components/form/td_form_item.dart +++ b/tdesign-component/lib/src/components/form/td_form_item.dart @@ -518,7 +518,7 @@ class _TDFormItemState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.all(16), // 仅作用于 TDText + padding: const EdgeInsets.all(16), child: TDText( widget.label ?? '', style: const TextStyle(fontSize: 16), @@ -697,8 +697,7 @@ class _TDFormItemState extends State { children: [ Expanded( child: TDText( - /// TODO: 选择器 结果展示部分 也可以单独设 API - textAlign: TextAlign.right, + textAlign: FormContentAlign, output, font: TDTheme.of(context).fontBodyLarge, textColor: From e5a0f130d7f0e8b1e35db68b764eef5f92f93b0c Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 28 Oct 2024 09:22:39 +0800 Subject: [PATCH 24/25] =?UTF-8?q?=E9=87=87=E7=94=A8=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E5=92=8C=E9=A2=84=E5=8A=A0=E8=BD=BD=E4=BC=98=E5=8C=96=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9E=84=E5=BB=BA=E6=80=A7=E8=83=BD=20TODO=EF=BC=9A?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/src/components/form/td_form_validation.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tdesign-component/lib/src/components/form/td_form_validation.dart b/tdesign-component/lib/src/components/form/td_form_validation.dart index 4de3587ae..39d9d12b2 100644 --- a/tdesign-component/lib/src/components/form/td_form_validation.dart +++ b/tdesign-component/lib/src/components/form/td_form_validation.dart @@ -15,11 +15,13 @@ class TDFormValidation { required this.type, }); - // 执行校验逻辑 + /// 执行校验逻辑 String? check(String? value) { if (validate(value) != null) { return errorMessage; } - return null; // 校验通过时返回 null + + /// 校验通过时返回 null + return null; } } From 87ccb06ccc4505d958aeef6017aa1cddcc97a89c Mon Sep 17 00:00:00 2001 From: Simon_Wzy <1691663479@qq.com> Date: Mon, 28 Oct 2024 09:23:48 +0800 Subject: [PATCH 25/25] =?UTF-8?q?=E9=87=87=E7=94=A8=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E5=92=8C=E9=A2=84=E5=8A=A0=E8=BD=BD=E4=BC=98=E5=8C=96=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9E=84=E5=BB=BA=E6=80=A7=E8=83=BD=20TODO=EF=BC=9A?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/src/components/form/td_form_validation.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tdesign-component/lib/src/components/form/td_form_validation.dart b/tdesign-component/lib/src/components/form/td_form_validation.dart index 39d9d12b2..afdf07be2 100644 --- a/tdesign-component/lib/src/components/form/td_form_validation.dart +++ b/tdesign-component/lib/src/components/form/td_form_validation.dart @@ -3,7 +3,8 @@ import '../../../tdesign_flutter.dart'; /// 实现普通表单项的校验 /// 校验规则 和 错误提醒 class TDFormValidation { - final String? Function(String?) validate; // 校验方法 + /// 校验方法 + final String? Function(String?) validate; final String errorMessage; /// 校验对象的类型