简体   繁体   English

在自定义小部件中调用方法

[英]Call a method inside custom widget

I have created a custom widget.我创建了一个自定义小部件。 It comprises of read only TextFormField with suffixed IconButton, API, Alert Dialog and callback function The widget can be in 2 states, set or reset.它包括带有后缀 IconButton 的只读 TextFormField、API、警报对话框和回调 function 小部件可以处于 2 种状态,设置或重置。

One put the widget in set condition by IconButton on TextFormField, this will execute an API call and the returned data is displayed on TextFormField.通过 TextFormField 上的 IconButton 将小部件置于设置状态,这将执行 API 调用,返回的数据显示在 TextFormField 上。
The widget is reset from the parent screens depending on some application requirement.根据某些应用程序要求,从父屏幕重置小部件。

I have imported and used this custom widget in my various activities (screens).我已经在我的各种活动(屏幕)中导入并使用了这个自定义小部件。 Their In my screen I wish clear my custom widget and I have created clear method.他们在我的屏幕上我希望清除我的自定义小部件,并且我已经创建了 clear 方法。

I wish to know who will I call this clearWidget method.我想知道我将把这个clearWidget方法称为谁。

If required I can clearWidget method to class GetTimeWidget extends StatefulWidget如果需要,我可以clearWidget方法到class GetTimeWidget extends StatefulWidget

enum TimeWidgetEvent { Start, Stop }

class GetTimeWidget extends StatefulWidget {
  Ref<String> time;
  final TimeWidgetEvent mode;
  final String label;
  const GetTimeWidget({
    required this.time,
    required this.mode,
    required this.label,
    Key? key,
  }) : super(key: key);

  @override
  State<GetTimeWidget> createState() => _GetTimeWidgetState();
}

class _GetTimeWidgetState extends State<GetTimeWidget> {
final TextEditingController controller;
  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: controller,
      readOnly: true,
      //initialValue: ,
      decoration: InputDecoration(
        label: Text(widget.label),
        hintText: 'Please Get ${widget.label} from sever',
        suffixIcon: TextButton.icon(
          onPressed: () {
            //Execute API to get time
          },
          icon: (widget.mode == TimeWidgetEvent.Start)
              ? const Icon(Icons.play_circle)
              : const Icon(Icons.stop_circle),
          label: (widget.mode == TimeWidgetEvent.Start)
              ? const Text('Start')
              : const Text('Stop'),
        ),
        border: const OutlineInputBorder(),
      ),
      validator: (value) {
        if (value == null || value.isEmpty) {
          return 'Please Get ${widget.label} from server'; //Validation error
        }
        return null; //Validation Success
      },
    );
  }
  
  void clearWidget()
  {
    controller.clear();
    //Execute API
  }
}

I think you can't.我认为你不能。 because the state class is private, and every method in that class (_GetTimeWidgetState) cannot called externally.因为 state class 是私有的,并且 class (_GetTimeWidgetState) 中的每个方法都不能从外部调用。 If I correctly understand what you want to do, is to change the internal state of _GetTimeWidgetState outside from this widget.如果我正确理解你想要做什么,就是从这个小部件外部更改 _GetTimeWidgetState 的内部 state。

I think you can't.我认为你不能。 My suggest is to use one of the state managers that you can find for flutter, like Riverpod (my choice), or Cubit, Get/Getx, etc... In that manner you can read/change the internal state using the global state managed by the state manager. My suggest is to use one of the state managers that you can find for flutter, like Riverpod (my choice), or Cubit, Get/Getx, etc... In that manner you can read/change the internal state using the global state由 state 管理器管理。

For example, with Riverpod you can define a StateClass that handles your data:例如,使用 Riverpod,您可以定义一个处理数据的 StateClass:

final myProvider = StateNotifierProvider<MyStateNotifier, MyState>((ref) {
    return MyStateNotifier("someInitialDataInfo");
 });

class MyStateNotifier extends StateNotifier<MyState> {
      MyStateNotifier("someInitialDataInfo") : super( MyState("someInitialDataInfo"));
    void clear(String someDataInfo)  { state = MyState( someDataInfo) ;}
}

@immutable
class MyState {
 ..... }

Then in your ComsumerState ( in Riverpod you should use ConsumerStatefulWidget and ConsumerState) you can watch the notifier as here:然后在您的 ComsumerState 中(在 Riverpod 中您应该使用 ConsumerStatefulWidget 和 ConsumerState),您可以在此处查看通知程序:

class _GetTimeWidgetState extends ConsumerState<GetTimeWidget> {
   final TextEditingController controller;

@override
  Widget build(BuildContext context, WidgetRef ref) {
   final myState = ref.watch(myProvider );
   if ( myState.someDataInfo == 'Clicked Reset!!!!' ) {
        controller.clear();
   }
   return TextFormField( .... );
 }
 .... } ...}

Now, observe that the build method will be called when the state inside the Notifier class would change.现在,观察当通知程序 class 内的 state 发生变化时,将调用构建方法。 Thus you will be notified once per change.因此,每次更改都会通知您一次。 Inside the StateNotifier class (the class you use to extend and to define your MyStateNotifier class) will do the following match to put your widget in the dirty-state:在 StateNotifier class(用于扩展和定义 MyStateNotifier 类的 class)内部将执行以下匹配以将您的小部件置于脏状态:

state != oldState

That means that every time you change the internal state field, it will put your widget to the the dirty state, and thus it will be re builded.这意味着每次您更改内部 state 字段时,它都会将您的小部件放入脏 state,因此它将被重新构建。 the MyState class is defined as @immutable , so every state change cannot not be done with something like: MyState class 被定义为@immutable ,因此每个 state 更改都不能通过以下方式完成:

 state.setMyField ( ' my value ' );

but will be done changing the state object itself:但将完成更改 state object 本身:

state =  MyState ( ... );

or with its copy method:或使用其复制方法:

 state = state.copyWith( .... ) ;

In this manner you avoid some side-effects ( the state should always be immutable )通过这种方式,您可以避免一些副作用( state 应该始终是不可变的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM