How do I make setState run from Class ? flutter - android

I need to use a command in class other
Example
I need to use a command in class other
Example
import 'package:flutter/material.dart';
class SelectionUser {
BuildContext _context;
var _pagy;
int n = 0;
open(int x) {
n = x * 10;
setState(() {}); //////////////////////////////
}
SelectionUser(this._context, this._pagy);
}

You can pass a VoidCallback parameter to your class like this:
import 'package:flutter/material.dart';
class Example extends State<...>{
#override
void initState(){
super.initState();
final user = SelectionUser(() => setState((){}), null)
}
...
}
class SelectionUser {
SelectionUser(this._setState, this._pagy);
var _pagy;
VoidCallback _setState;
int n = 0;
open(int x) {
n = x * 10;
_setState(); //////////////////////////////
}
}
Then your user.open() will call the _setState callback that triggers the setState as required

The fact that you need a BuildContext in your class and you want to call setState makes it obvious that you should not have a simple class, but instead inherit from StatefulWidget and State<>.
More information on how to do so can be found in the documentation.

Related

2 Problems from Flutter Beginner Course from Angela, Clima project after refactoring code

1) From loading_screen.dart :
Error : Instance member 'getData' can't be accessed using static access.
Locator( ) is my location handling class.
import 'package:flutter/material.dart';
import 'package:clima/services/location_handler.dart';
import 'package:clima/services/networking.dart';
const myAPI = 'cant post api online but its just alphabets and numbers passed as a string';
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
late double latitood;
late double longitood;
void initState() {
//this method is called the moment we run our app.
super.initState();
getLocationData();
}
void getLocationData() async {
Locator loca = Locator();
await loca.getCurrentLocation();
latitood = loca.latitude;
longitood = loca.longitude;
NetworkHelper NetHelp = NetworkHelper(
//pasing url info into Network Helper class.
'https://api.openweathermap.org/data/2.5.weather?lat=$latitood&lon=$longitood&appid=$myAPI');
var weatherDataFinal = await NetworkHelper.getData();
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
2) From networking.dart :
Error : The argument type 'String' can't be assigned to the parameter type 'Uri'.
import 'dart:convert'; /
import 'package:http/http.dart' as http;
class NetworkHelper {
NetworkHelper(this.url);
final String url;
Future getData() async {
http.Response response = await http.get(url);
//passing url as a single string to get method to get Response.
if (response.statusCode == 200) {
String data = response.body;
var decodedData = jsonDecode(data);
//decoding and putting data into decodedData variable of dynamic type.
return decodedData;
} else {
print(response.statusCode);
}
}
}
Did someone encounter these problems ? If you did and found a Solution then please help me !!!!
This await NetworkHelper.getData(); should be await NetHelp.getData(); because that is how you named your variable.
await http.get(url); should be await http.get(Uri.parse(url));

Flutter how to migrate this BLoC old version code to Bloc new version

how i must write this code in bloc v.8 i don know how i see some searches but im not understand and this is my code for classes they give me error => StateError (Bad state: add(DoFetchEvent) was called without a registered event handler.
Make sure to register a handler via on((event, emit) {...})):
class PostBloc extends Bloc<PostEvent, PostState> {
PostRepository repo;
PostBloc(PostState initialState, this.repo) : super(initialState);
Stream<PostState> mapEventToState(PostEvent event) async* {
if (event is DoFetchEvent) {
yield LoadingState();
try {
var posts = await repo.fetchPosts();
yield FetchSuccess(posts: posts);
} catch (e) {
yield ErrorState(message: e.toString());
}
}
}
}
import 'package:equatable/equatable.dart';
class PostEvent extends Equatable {
#override
List<Object?> get props => [];
}
class DoFetchEvent extends PostEvent {}
class PostState extends Equatable {
#override
List<Object?> get props => [];
}
class InitialState extends PostState {}
class LoadingState extends PostState {}
class FetchSuccess extends PostState {
List<PostModel> posts;
FetchSuccess({required this.posts});
}
class ErrorState extends PostState {
String message;
ErrorState({required this.message});
}
void main() {
runApp(MaterialApp(
home: BlocProvider(
create: (context) => PostBloc(InitialState(), PostRepository()),
child: MyApp(),
),
));
}
You can set your InitialState directly in the super constructor without manually passing it in like so.
PostBloc(this.repo) : super(InitialState()) {
on<DoFetchEvent>(_onDoFetchEvent);
}
Then you no longer pass in any state in the BlocProvider
BlocProvider<PostBloc>(
create: (BuildContext context) => PostBloc(PostRepository()),
...
Then your mapEventToState gets replaced with a method that takes the relevant event, and an Emitter<PostState> as arguments. yield then gets replaced with emit in the method.
Your whole class would look like this.
PostBloc(this.repo) : super(InitialState()) {
on<DoFetchEvent>(_onDoFetchEvent);
}
_onDoFetchEvent(
DoFetchEvent event,
Emitter<PostState> emit,
) async {
emit(LoadingState());
try {
var posts = await repo.fetchPosts();
emit(FetchSuccess(posts: posts));
} catch (e) {
emit(ErrorState(message: e.toString()));
}
}
}
That should do it.
Besides that, you're probably getting linter warnings about must_be_immutable on your state classes because PostState extend Equatable.
So I suggest making all PostState parameters final and adding the props override from Equatable to your state classes.
class ErrorState extends PostState {
final String message;
ErrorState({required this.message});
#override
List<Object?> get props => [message];
}

How hold the splash screen till data are ready

Is it possible that the spash screen (launch screen)
is shown till the data needed for the app is ready?
Are there other options in manifest.xml as below?
"io.flutter.app.android.SplashScreenUntilFirstFrame"
After many retries I found a solution which could be optimized.
Please tell me your opinion
Normally flutter starts with
void main() => runApp(new MyApp());
I inserted the data acquisition on the begin by modifying the code
void main() async {
final OrderedAppList aList = new OrderedAppList(); //class to get all data
var funx = (int) async => aList.getit(); //to get all of the data
var value;
value = await funx(1); //should wait for the return value
runApp(new MyApp(
qallUserApps: aList.allUserApps,
qlistLen: value, // means aList.listLen,
qplatformVersion: aList.platformVersion,
qmodel: aList.model
));
}
And in MyApp:
class MyApp extends StatelessWidget {
final List qallUserApps;
final int qlistLen;
final String qplatformVersion;
final String qmodel;
// Constructor:
const MyApp({Key key, this.qallUserApps,
this.qlistLen,
this.qplatformVersion,
this.qmodel})
: super(key: key);
#override
Widget build(BuildContext context) {
// ...
}
Code part of the class OrderedAppList:
class OrderedAppList {
int listLen= -1;
String platformVersion = "Unknown Platform";
String model = "Unknown Platform";
List allUserApps = null;
Future<int> getit() async {
try {
allUserApps = await AppsAsStateless.allApps;
listLen = allUserApps.length;
} on Exception {
allUserApps = null;
listLen = 0;
}
// ...
return listLen ;
}
Thanks for reading this!
it works fine and
the code in main can be optimized:
void main() async { // async that data acquisition done before any widgets shown
final OrderedAppList aList = new OrderedAppList();
int value;
value = await aList.getit();
runApp(new MyApp(
qallUserApps: aList.allUserApps,
qlistLen: value, // = aList.listLen,
qplatformVersion: aList.platformVersion,
qmodel: aList.model
));
}

String xml file in Flutter

In flutter string text are directly set to the TextField widget like:
new Text('Hello, How are you?')
Is correct way ? or we can maintain all string in one file and use it like:
<string name="name_hint">Hello, How are you?</string>
Is it possible ?
Flutter currently doesn’t have a dedicated resources-like system for strings. At the moment, the best practice is to hold your copy text in a class as static fields and accessing them from there. For example:
class Strings {
static const String welcomeMessage = "Welcome To Flutter";
}
Then in your code, you can access your strings as such:
Text(Strings.welcomeMessage)
source
Edit May '19:
There's now this package that allows you to create json files with your Strings. It will allow you to create Strings for plurals, genders and languages etc
You can create a separate json file for each language like so:
string_en.json
{
"thanks": "Thanks."
}
string_nl.json
{
"thanks": "Dankjewel."
}
And then use this to access it
S.of(context).thanks;
It will know which language to choose based on your phone's default language.
Screenshot:
Full Code (Null safe):
For those of you who don't want to use any 3rd party plugin, here is how you can do it.
Create a folder strings in assets. Put your language file in it.
assets
strings
- en.json // for english
- ru.json // for russian
Now in en.json, write your string, for example.
{
"text1": "Hello",
"text2": "World"
}
Similarly, in ru.json,
{
"text1": "Привет",
"text2": "Мир"
}
Add this to pubspec.yaml file (mind the spaces)
flutter:
uses-material-design: true
assets:
- assets/strings/en.json
- assets/strings/ru.json
flutter_localizations:
sdk: flutter
Now you are all set to use these strings in your app. Here is the sample code, the AppBar shows the translated text.
void main() {
runApp(
MaterialApp(
locale: Locale("ru"), // switch between en and ru to see effect
localizationsDelegates: [const DemoLocalizationsDelegate()],
supportedLocales: [const Locale('en', ''), const Locale('ru', '')],
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(DemoLocalizations.of(context).getText("text2") ?? "Error")),
);
}
}
// this class is used for localizations
class DemoLocalizations {
static DemoLocalizations? of(BuildContext context) {
return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
}
String getText(String key) => language[key];
}
late Map<String, dynamic> language;
class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {
const DemoLocalizationsDelegate();
#override
bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode);
#override
Future<DemoLocalizations> load(Locale locale) async {
String string = await rootBundle.loadString("assets/strings/${locale.languageCode}.json");
language = json.decode(string);
return SynchronousFuture<DemoLocalizations>(DemoLocalizations());
}
#override
bool shouldReload(DemoLocalizationsDelegate old) => false;
}
You can use the methods represented in the internationalization sections of the documentation to control both centralized string management and translations (if you need translations)
https://flutter.io/tutorials/internationalization/
It might be overkill for a simple app with only a few strings though.
I would separate these classes into individual files, but just to explain my approach for this question.
I have a base class which has my strings getters. Every language I want to support I have to create a class which extends from this class and override its getters. Thus, whenever I create a string, I have to override each implementation of this base class. It is helpful to avoid forgetting to create some locale specific string.
/// Interface strings
class Strings {
String get hello;
}
/// English strings
class EnglishStrings extends Strings {
#override
String get hello => 'Hello';
}
/// Russian strings
class RussianStrings extends Strings {
#override
String get hello => 'Привет';
}
/// Portuguese strings
class PortugueseStrings extends Strings {
#override
String get hello => 'Olá';
}
After that, in a global scope of your application, you could declare a unique instance of the locale you want to use (using a singleton is a good option).
Just showing a short example of using it:
class Resources {
BuildContext _context;
Resources(this._context);
Strings get strings {
// It could be from the user preferences or even from the current locale
Locale locale = Localizations.localeOf(_context);
switch (locale.languageCode) {
case 'pt':
return PortugueseStrings();
case 'ru':
return RussianStrings();
default:
return EnglishStrings();
}
}
static Resources of(BuildContext context){
return Resources(context);
}
}
And finally, using it in some widget:
Text(Resources.of(context).strings.hello)
Using an extension from BuildContext
You can extend BuildContext to create some particular features and give more power to your application.
This is available from Dart 2.7. See more.
app_context_extension.dart
extension AppContext on BuildContext {
Resources get resources => Resources.from(this);
}
favorites_page.dart
import 'package:flutter/material.dart';
// you have to import it yourself. The auto import does not work in this case
import 'package:myapp/ui/extensions/app_context_extension.dart';
class FavoritesPage extends StatefulWidget {
#override
_FavoritesPageState createState() => _FavoritesPageState();
}
class _FavoritesPageState extends State<FavoritesPage> {
#override
Widget build(BuildContext context) {
return Text(context.resources.strings.hello);
}
}
Using GlobalKey
Along with an extension of BuildContext as shown above, you can also use GlobalKey.
Basically, you could use it when you do not have a context instance.
This last one has a good advantage. You could use strings anywhere in your application. In other words, if you use some pattern like MVC for instance and want to use strings in your controllers, you could easily do it.
You can declare something like this:
application.dart
import 'package:myapp/ui/extensions/app_context_extension.dart';
import 'package:myapp/ui/values/resources.dart';
import 'package:flutter/material.dart';
class Application {
static GlobalKey<NavigatorState> navKey = GlobalKey();
static Resources get resources {
return navKey.currentContext.resources;
}
}
main.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: Application.navKey,
...
And then:
import 'package:flutter/material.dart';
import 'package:myapp/application/application.dart';
class FavoritesPage extends StatefulWidget {
#override
_FavoritesPageState createState() => _FavoritesPageState();
}
class _FavoritesPageState extends State<FavoritesPage> {
#override
Widget build(BuildContext context) {
return Text(Application.resources.strings.hello);
}
}
Hope it helps!
First of all, create a new strings folder in assets and add your language JSON files.
assets
strings
- en.json
- ar.json
This is your en.json file
{
"title": "Flutter app"
}
And this is your ar.json file
{
"title": "تطبيق Flutter"
}
Then, change your pubspec.yaml file like below.
dependencies:
# your other codes
intl: ^0.17.0
flutter_localizations:
sdk: flutter
# your other codes
flutter:
uses-material-design: true
assets:
- assets/strings/en.json
- assets/strings/ar.json
After that, create AppLocalizations.dart class
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
String getText(String key) => language[key];
}
Map<String, dynamic> language;
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
#override
bool isSupported(Locale locale) => ['en', 'ar'].contains(locale.languageCode);
#override
Future<AppLocalizations> load(Locale locale) async {
String string = await rootBundle.loadString("assets/strings/${locale.languageCode}.json");
language = json.decode(string);
return SynchronousFuture<AppLocalizations>(AppLocalizations());
}
#override
bool shouldReload(AppLocalizationsDelegate old) => false;
}
Finally in your main.dart file make the below changes
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: AppLocalizations.of(context).getText("title"),
locale: Locale("en"),
localizationsDelegates: [const AppLocalizationsDelegate()],
supportedLocales: [const Locale('en', ''), const Locale('ar', '')],
home: HomeScreen(),
);
}
}
create "Strings.dart" file and add the below line==>
class Strings
{
static String welcomeScreen="WelCome Page";
static String loadingMessage="Loading Please Wait...!";
}
And then call the file using the below line using the widget
Text(Strings.loadingMessage)
Make sure that the String.dart file has been imported
I use this method instead of using third party lib. Basically, I create a class that holds those values (string, colors, dimens, etc)
resources.dart
import 'dart:ui';
class ResString{
var data = {
'url' : 'https://facebook.com/',
'welcome' : 'Welcome Home',
};
String get(String key){
return data[key];
}
}
class ResColor{
var data = {
'colorPrimary' : 0xff652A04,
'colorPrimaryDark' : 0xffFFFFFF,
'colorPrimaryLight' : 0xffF6EDDD,
};
Color get(String key){
return Color(data[key]);
}
}
To use it, simply call the get method
main.dart
import 'package:my_app/resources.dart';
...
return Container(
color: ResColor().get('colorPrimary')
);
...
It's not funny to mange the languages at all, Android Studio have a build-in plugin of Transalte the words and let you mange it easy, so you can see in a table the Key of the word, and the result in every language you just add, manually of course. soon in Flutter I hope!
I tried some of the solutions suggested in this post, but the one from #Fakhriddin Abdullaev was the one that worked well for me. But I didn't like the fact that one must always lookup the key of each string in the.json files.
So I created a strings.dart:
import 'package:/AppLocalizations.dart';
class Strings {
static String error = "Error Message";
static AppLocalizations? locator = AppLocalizations();
// ignore: non_constant_identifier_names
static String app_name = locator?.getText("app_name") ?? error;
}
When there is an entry in the .json files like:
{
"app_name" : "My awesome AppName",
}
you just need to call strings. and the code completion will suggest needed string:
But do not forget to initialize Strings.locator with the correct context:
Strings.locator = AppLocalizations.of(context);
That is the correct way. In flutter you don't need .xml or .css files to manage your layout/stuff.
Everything is managed using the dart code. Which makes everything much easier.

Can I call Kotlin function from Dart

Using Flutter, a kotlin/swift function can be called by something like:
file.dart:
static const platform = const MethodChannel('my.test.flutterapp/battery');
final int result = await platform.invokeMethod('getBatteryLevel');
file.kt:
private val CHANNEL = "my.test.flutterapp/battery"
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "getBatteryLevel") {
...
} else {
result.notImplemented()
}
}
Is there something similar to call Kotlin function from standard Dart app, like Dart console app!
https://flutter.io/developing-packages/
Plugin packages: A specialized Dart package which contain an API written in Dart code combined with a platform-specific implementation for Android (using Java or Kotlin), and/or for iOS (using ObjC or Swift). A concrete example is the battery plugin package.
...
flutter create --template=plugin -i swift -a kotlin hello
For the VM the mechanisms available are basic OS operations and native extensions.
By OS operations I mean, you could launch a separate process and interact with it, using files or the network stack. This is probably not as fine grained as you're looking for.
Native extensions allow you to call out to C or C++ code. I don't know enough about kotlin to know if you can easily expose functionality to C/C++. If it's possible, this will give you the tightest integration.
https://www.dartlang.org/articles/dart-vm/native-extensions
You can see this project: Full Sample
In Andriod:
class MainActivity: FlutterActivity() {
private val DATA_CHANNEL = "app.channel.shared.data"
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), DATA_CHANNEL).setMethodCallHandler { call, result ->
if (call.method!!.contentEquals("getSharedText")) {
result.success("Shared Text")
}
}
}
}
In Dart:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
static const platform = const MethodChannel('app.channel.shared.data');
String dataShared = "No Data";
#override
void initState() {
super.initState();
getSharedText();
}
getSharedText() async {
var sharedData = await platform.invokeMethod("getSharedText");
if (sharedData != null) {
setState(() {
dataShared = sharedData;
});
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home:Scaffold(body: Center(child: Text(dataShared)))
);
}
}

Categories

Resources