Flutter中如何在ReactiveForm内动态修改输入框边框样式?
To achieve your desired behavior—showing cEnabledBorder when the input is valid and unfocused, and cInitialBorder when invalid or untouched—you need to dynamically adjust the enabledBorder property based on the form control's validation state. Here's how to fix it:
Step-by-Step Implementation
The key is to leverage the builder callback of ReactiveTextField, which gives you real-time access to the form control's state (validity, focus, etc.). This lets you update the border styles dynamically as the control's state changes.
ReactiveTextField<String>( onSubmitted: () => form.focus('full_name'), autofocus: false, formControlName: 'full_name', onEditingComplete: () {}, validationMessages: (control) => { ValidationMessage.required: StringConst.signupFormFullNameValidate, }, textInputAction: TextInputAction.next, // Use the builder to access the live FormControl state builder: (context, control, child) { return TextField( controller: control.valueAccessor, focusNode: control.focusNode, textInputAction: TextInputAction.next, onSubmitted: () => form.focus('full_name'), decoration: InputDecoration( errorMaxLines: 2, // Dynamic enabled border: use cEnabledBorder if valid, else cInitialBorder enabledBorder: control.valid ? cEnabledBorder : cInitialBorder, focusedBorder: cFocusedBorder, errorBorder: cErrorBorder, focusedErrorBorder: cFocusedErrorBorder, labelText: StringConst.fullName, labelStyle: tBody3, floatingLabelStyle: tFloatLabel, errorStyle: tError.copyWith( overflow: TextOverflow.clip, ), errorText: control.errorMessage, // Pass validation error directly ), ); }, )
Why This Works
- The
buildercallback provides the currentFormControlinstance, so we can check itsvalidproperty in real time. - The
enabledBorderproperty defines the border style when the input is enabled and not focused. By setting it tocEnabledBorderonly when the control is valid, we ensure the style sticks after the input loses focus (as long as validation passes). - When the input is invalid,
enabledBorderfalls back tocInitialBorder, matching your original default state. - We reuse the control's
valueAccessorandfocusNodeto maintain ReactiveForms functionality (like form control binding and focus management).
Alternative Approach (Without Builder)
If you prefer not to use the builder, you can directly reference the form control in the InputDecoration—just make sure the widget reacts to state changes. You can do this by wrapping the ReactiveTextField in a ValueListenableBuilder that listens to the control's validity:
ValueListenableBuilder<AbstractControl<String>>( valueListenable: form.control('full_name'), builder: (context, control, child) { return ReactiveTextField<String>( onSubmitted: () => form.focus('full_name'), autofocus: false, formControlName: 'full_name', onEditingComplete: () {}, validationMessages: (control) => { ValidationMessage.required: StringConst.signupFormFullNameValidate, }, textInputAction: TextInputAction.next, decoration: InputDecoration( errorMaxLines: 2, enabledBorder: control.valid ? cEnabledBorder : cInitialBorder, focusedBorder: cFocusedBorder, errorBorder: cErrorBorder, focusedErrorBorder: cFocusedErrorBorder, labelText: StringConst.fullName, labelStyle: tBody3, floatingLabelStyle: tFloatLabel, errorStyle: tError.copyWith( overflow: TextOverflow.clip, ), ), ); }, )
This achieves the same result but uses ValueListenableBuilder to trigger updates when the control's validity changes.
内容的提问来源于stack exchange,提问作者Pixxu Waku

