Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a custom controller in Flutter

I created a widget named InfiniteScroll which handles asynchronously loaded data and renders it with ListView.builder. However I am having trouble creating a controller for it (for example for clearing all the loaded data). I read through the implementation of existing controllers such as TextEditingController but I can't seem to wrap my head around it. Here's an example of what I'm trying to achieve:

// I have
InfiniteScroll(
  fetchMore: () async {}, // fetching more data
  builder: (data) {}, // building an item
)

// need
InfiniteScroll(
  controller: _infiniteScrollController,
  fetchMore: () async {}, // fetching more data
  builder: (data) {} // building an item
)
// later
_infiniteScrollController.clearItems();

How to create such a controller? I am using flutter_hooks for local state management if that matters.

like image 521
Marcin Avatar asked Nov 30 '22 13:11

Marcin


2 Answers

I don't think the answer of @ValdaXD describes a good solution.

The way this is usually solved, also in native Flutter widgets like TextField or ScrollController is a controller class that extends ChangeNotifier.

The controller would handle the items and provide a public API to clear them:

class InfiniteScrollController extends ChangeNotifier {
  List<Widget> items = [];

  void clearItems() {
    items.clear();
    notifyListeners();
  }
}

The widget could then display the items via the injected controller:

class InfiniteScroll extends StatefulWidget {
  InfiniteScroll({
    required this.controller
  });

  final InfiniteScrollController controller;

  @override
  State<StatefulWidget> createState() {
    return _InfiniteScrollState();
  }
}

class _InfiniteScrollState extends State<InfiniteScroll> {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: widget.controller.items,
    );
  }
}

I have created a blog post with a different example but the same topic: a controller for a custom widget: https://www.flutterclutter.dev/flutter/tutorials/create-a-controller-for-a-custom-widget/2021/2149/

like image 178
Schnodderbalken Avatar answered Dec 04 '22 02:12

Schnodderbalken


I just pass the functions that i want to expose to the controller.

typedef MyTypedef(int value);

class MyController {
  VoidCallback myFunction;
  VoidCallback mySecondFunction;
  MyTypedef functionThatReturns;

  void dispose() {
    //Remove any data that's will cause a memory leak/render errors in here
    myFunction = null;
    mySecondFunction = null;
    functionThatReturns = null;
  }
}

class MyWidget extends StatefulWidget {
  const MyWidget({this.controller});
  final MyController controller;
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    MyController _controller = widget.controller;
    if (_controller != null) {
      _controller.myFunction = firstFunction;
      _controller.mySecondFunction = secondFunction;
      _controller.functionThatReturns = functionWithInt;
    }
  }

  void firstFunction() {
    print('Calling first function');
  }

  void secondFunction() {
    print('Calling second function');
  }

  void functionWithInt(int value) {
    print('Calling third function with value $value');
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Then the usage is easy

//We create a variable somewhere
  ...
  MyController controller;
  ...

  //We initialize it
  ...
  controller = MyController();
  ...

  //We assign it
  @override
  Widget build(BuildContext context) {
    return MyWidget(controller: controller);
  }
}

//When we cant to call a function
...
controller.myFunction();
...

//When we want to dispose it
...
controller.dispose();
...

There is a little work to be done to avoid null exceptions , per example we could check if the controller references are null before calling the functions, and throw an error, but that's up to you to decide.

like image 34
ValdaXD Avatar answered Dec 04 '22 04:12

ValdaXD