I want to create a base class for my Flutter widgets:
import 'package:flutter/widgets.dart';
abstract class State extends State {
#override
Widget build(BuildContext context) {
// ...
}
// ...
}
Like this, it results in the error "State' can't extend itself." which makes perfect sense. To fix it I can do this:
import 'package:flutter/widgets.dart' as base;
abstract class State extends base.State {
But now I have to prefix all other framework classes with "base.". Is there a way to alias just the State class and use everything else without a prefix?
This seems to have worked:
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as base show State;
abstract class State<T extends StatefulWidget> extends base.State {
#override
Widget build(BuildContext context) {
// ...
}
}
Related
I need to initialize get_it right in the widget file so that it would be available down the widget three. Normally we would do it next to runApp() but here I need it for demonstration purposes.
Is it a correct place to initialize it?
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'form_store.dart';
final getIt = GetIt.instance;
class FormExample extends StatefulWidget {
const FormExample();
#override
_FormExampleState createState() => _FormExampleState();
}
class _FormExampleState extends State<FormExample> {
final store = getIt.get<FormStore>();
#override
void initState() {
super.initState();
getIt.registerSingleton<FormStore>(FormStore());
store.setupValidations();
}
...
// in the same .dart file
// this widget will be used in build method of the above FormExample class
class InnerPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final store = GetIt.I<FormStore>();
return Scaffold(
body: Center(child: Text('Hello ${store.name}')),
);
}
}
I have created a widget in Flutter as follows:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class WidgetA<T> extends StatefulWidget {
const WidgetA({
super.key,
required this.errorSelector,
...
});
final Function errorSelector;
...
#override
State<WidgetA> createState() =>
_WidgetAState<T>();
}
class _WidgetAState<T> extends State<WidgetA> {
...
#override
Widget build(BuildContext context) {
...
return Builder(
builder: (ctx) {
final String foo =
ctx.select(widget.errorSelector as String Function(T));
return Text(foo);
}
);
}
}
Is this practice okay?
Are there better ways to accomplish this?
Can this cause any issues?
FYI - T is being used to pass a Class that extends a Bloc.
it's not bad and it's not good unless you have a good reason to do it (for example if you want to customize a data type based on that generic ).
so before doing it, ask yourself why so I need to make it generic, all the good patterns in the code are there to add some value to the code.
as you can see the only place where the generic is important is to set it in the State object, this prevents conflicting your StatefulWidget in your app with others and specify it to one StatefulWidget
I have a class called GetConnectApiHelper that implemented an abstraction called IApiHelper, I need to register this class with Get.put inside Bindings and retrieve the implementation inside an abstraction variable but when I try to do that I get an error about "the abstraction is not registered".
How can I inject the dependency correctly making it easy to change in case I need to replace with http, dio etc...(clean architecture)
abstract class IApiHelper {}
class GetConnectApiHelper extends GetxService implements IApiHelper {}
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put(GetConnectApiHelper());
Get.put(SignInController());
}
}
class SignInController extends GetxController {
final IApiHelper apiHelper = Get.find(); // This throws the exception
}
======== Exception caught by widgets library =======================================================
The following message was thrown building Builder(dirty):
"IApiHelper" not found. You need to call "Get.put(IApiHelper())" or "Get.lazyPut(()=>IApiHelper())"
I found a solution. I can set the Interface as a Type and then register the implementation I want to be retrieved.
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put<IApiHelper>(GetConnectApiHelper());
Get.put(SignInController());
}
}
class SignInController extends GetxController {
final IApiHelper apiHelper = Get.find();
}
print(apiHelper.runtimeType); // it prints Instance of 'GetConnectApiHelper'
Or I can inject the implementation.
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put<IApiHelper>(GetConnectApiHelper());
Get.put(SignInController(apiHelper: Get.find()));
}
}
class SignInController extends GetxController {
final IApiHelper apiHelper;
SignInController({required this.apiHelper})
}
GetX finds its dependencies based on its exact types so you need to use Get.find<GetConnectApiHelper>()
updated:
class SignInBinding extends Bindings {
#override
void dependencies() {
Get.put(GetConnectApiHelper());
Get.put(SignInController<GetConnectApiHelper>());
}
}
class SignInController<T extends IApiHelper> extends GetxController {
final IApiHelper apiHelper = Get.find<T>();
}
I'd like to use the Logger library in my app. I only want to instasiate it once so that I have consistent formatting across my app, instead of passing PrettyPrinter in each file I use it. What is the right way of doing this? Should I just use a global const? Is there a way to do this using a Singleton?
I define a helper function to get the Logger:
import 'package:logger/logger.dart';
import 'log_printer.dart';
Logger getLogger(String className) {
return Logger(printer: SimpleLogPrinter(className));
}
Then in each class where I want logging for eaxmple:
class ProfileService with ChangeNotifier {
static final _log = getLogger('ProfileService');
Future<Profile> updateProfile(Profile profile) async {
_log.v('updateProfile');
...
}
...
}
Another example:
class AuthScreen extends StatelessWidget {
final log = getLogger('AuthScreen');
#override
Widget build(BuildContext context) {
log.v('build called');
...
}
...
}
I am currently refactoring my code to the bloc pattern and have created a bloc for a screen that fetches a list of locations from a json file in assets. The event being the fetch, and the states being initial, loading and loaded.
On my UI screen, I want to use BlocBuilder but when I use the BlocBuilder widget it gives me the error :
LocationListBloc doesnt extend Bloc with the LocationListBloc underlined with a line
My code is structured in folders as as follows
lib/blocs/location_list_bloc
lib/blocs/location_list_event
lib/blocs/location_list_state
lib/blocs/blocs
UI / location_list
location_list_state
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gt_project_bloc/blocs/blocs.dart';
class Locations extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<LocationListBloc, LocationListState>();
}
}
import 'package:equatable/equatable.dart';
import 'package:gt_project_bloc/models/models.dart';
import 'package:meta/meta.dart';
import 'package:equatable/equatable.dart';
abstract class LocationListState extends Equatable {
const LocationListState();
#override
List<Object> get props => [];
}
class LocationListinitial extends LocationListState {}
class LocationListLoading extends LocationListState {}
class LocationListLoaded extends LocationListState {
final List<SavedStations> locationlist;
LocationListLoaded(this.locationlist) : assert(locationlist != null);
}
location_list_event
import 'package:equatable/equatable.dart';
abstract class LocationListEvent extends Equatable {
#override
List<Object> get props => [];
}
class Fetch extends LocationListEvent {}
location_list_state
import 'package:equatable/equatable.dart';
import 'package:gt_project_bloc/models/models.dart';
import 'package:meta/meta.dart';
import 'package:equatable/equatable.dart';
abstract class LocationListState extends Equatable {
const LocationListState();
#override
List<Object> get props => [];
}
class LocationListinitial extends LocationListState {}
class LocationListLoading extends LocationListState {}
class LocationListLoaded extends LocationListState {
final List<SavedStations> locationlist;
LocationListLoaded(this.locationlist) : assert(locationlist != null);
}
I found my issue, i had a stateful widget on the same page called LocationList and it was confusing its state LocationListState with the same name of my blocs state