I am wanting to repeat the handleImages() method every five seconds but having an issue getting this to work.
import 'package:flutter/material.dart';
class CameraImageWidget extends StatefulWidget {
const CameraImageWidget({
Key key,
}) : super(key: key);
#override
_CameraImageWidgetState createState() => _CameraImageWidgetState();
}
class _CameraImageWidgetState extends State<CameraImageWidget> {
String handleImages() {
List<String> cameraImages = [
'assets/images/imageUpload.gif',
'assets/images/imageUploadGreen.gif',
];
String randomImage = (cameraImages..shuffle()).first;
return randomImage;
}
#override
Widget build(BuildContext context) {
return Image.asset(handleImages(), height: 450.0);
}
}
This should do the trick. Have not tested it tho.
class _CameraImageWidgetState extends State<CameraImageWidget> {
String _image;
#override
initState(){
handleImages();
}
void handleImages() async{
List<String> cameraImages = [
'assets/images/imageUpload.gif',
'assets/images/imageUploadGreen.gif',
];
setState(() {
_image = (cameraImages..shuffle()).first;
});
//Wait 5 seconds
await new Future.delayed(const Duration(seconds:5));
handleImages();
}
#override
Widget build(BuildContext context) {
return Image.asset(_image, height: 450.0);
}
}
import 'dart:async';
import 'package:flutter/material.dart';
class CameraImageWidget extends StatefulWidget {
const CameraImageWidget({
Key key,
}) : super(key: key);
#override
_CameraImageWidgetState createState() => _CameraImageWidgetState();
}
class _CameraImageWidgetState extends State<CameraImageWidget> {
String handleImages() {
String chosenImage;
List<String> cameraImages = [
'assets/images/imageUpload.gif',
'assets/images/imageUploadGreen.gif',
];
Timer.periodic(Duration(seconds: 10), (timer) {
setState(
() {
chosenImage = (cameraImages..shuffle()).first;
},
);
});
return chosenImage;
}
#override
Widget build(BuildContext context) {
return Image.asset(handleImages(), height: 400.0);
}
}
I made a dartpad.dev of the following code so that you can run it yourself. (however, instead of images, I am just showing the "asset text" every 5 seconds since it's on dartpad. You would just have to insert the text into the Image.asset using Image.asset(randomImage, height: 450.0);
Here's the dartpad: http://dartpad.dev/2af9c2d7c4b3436dfa55348bb4fb9dca
and here's the code:
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CameraImageWidget(),
);
}
}
class CameraImageWidget extends StatefulWidget {
const CameraImageWidget({
Key key,
}) : super(key: key);
#override
_CameraImageWidgetState createState() => _CameraImageWidgetState();
}
class _CameraImageWidgetState extends State<CameraImageWidget> {
static List<String> cameraImages = [
'assets/images/imageUpload.gif',
'assets/images/imageUploadGreen.gif',
];
String randomImage = (cameraImages..shuffle()).first;
int count = 0;
#override
initState() {
handleImages();
}
handleImages() {
Timer.periodic(Duration(seconds: 5), (timer) {
setState(() {
randomImage = (cameraImages..shuffle()).first;
print(randomImage);
count++;
print(count);
});
});
}
#override
Widget build(BuildContext context) {
// return Image.asset(handleImages(), height: 450.0);
return Text(randomImage); //
}
}
Related
is there a way to trigger the page navigation when a specific variable in provider class changes?
for example.
I want to navigate to login screen whenever the appLock variable becomes true otherwise do nothing
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
runApp(MultiProvider(providers: [
ChangeNotifierProvider(create: (_) => AppLockHelper()),
], child: const MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
context.read<AppLockHelper>().startThread();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: kWhiteColor,
),
supportedLocales: L10n.all,
initialRoute: '/',
onGenerateRoute: RouteGenerator.generateRoute,
);
}
}
and this is my provider class
class AppLockHelper extends ChangeNotifier {
bool _appLocked = false;
bool get appLocked => _appLocked;
final _get = GenericGetApi();
Timer? timer;
void startThread() {
timer = Timer.periodic(
const Duration(seconds: 15), (Timer t) => getAppStatus());
}
void stopThread() {
timer?.cancel();
}
Future<void> getAppStatus() async {
var appStatusResult =
await _get.get(endpoint: EndPointsPool.getAppLockStatus);
appStatusResult.fold((l) {
_appLocked = false;
}, (r) {
AppLock appLockResult = AppLock.fromJson(r);
_appLocked = appLockResult.applocked;
});
notifyListeners();
}
}
Okay the solution would be add a listner in initState.
#override
void initState() {
super.initState();
final myNotifier = context.read<AppLockHelper>();
void listener() {
myNotifier.appLocked
? Navigator.pushNamedAndRemoveUntil(context, "/log-in", (_) => false)
: null;
}
myNotifier.addListener(listener);
}
I am using GetX. I need to listen changes in TextController. The follow code do not work:
class Controller extends GetxController{
final txtList = TextEditingController().obs;
#override
void onInit() {
debounce(txtList, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
}
Is does not print nothing when I am changing txtList value from UI. I suppose it's because it does not check text field inside txtList.
How to get it work?
You need to pass an RxInterface into debounce to do this via GetX. Just create an RxString and add a listener to the controller then pass the RxString into debounce.
class Controller extends GetxController {
final txtList = TextEditingController();
RxString controllerText = ''.obs;
#override
void onInit() {
txtList.addListener(() {
controllerText.value = txtList.text;
});
debounce(controllerText, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
}
Then on any page in the app you can pass in that controller into the textfield and it'll print the value after the user stops typing for 1 second.
class Home extends StatelessWidget {
final controller = Get.put(Controller());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(controller: controller.txtList), // this will print
),
);
}
}
And if you need that value for anything else it's also always accessible via controller.controllerText.value.
By TextEditingController.text, we can already get changing text input value so it does not need .obs.
To pass parameter for debounce, we should pass value itself : txtList.text. (see here: https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md)
final txtList = TextEditingController(); // 1. here
#override
void onInit() {
debounce(txtList.text, (_) { // 2. here
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
This might work.
=================== added 11/21 ==================
Here's the example. I know the RxString variable seems a duplication for TextEditingController.text, but GetX's debounce function needs RxString type variable as a parameter. I tried to find more elegant way to do this, but I couldn't find anything. Please let me know if somebody knows a better way.
// in controller
late final TextEditingController textController;
final RxString userInput = "".obs;
#override
void onInit() {
super.onInit();
textController = TextEditingController();
userInput.value = textController.text;
textController.addListener(() {
userInput.value = textController.text;
}
);
debounce(userInput, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
}
check this snippet for example to listen to TextEditingController text change listener
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(),
darkTheme: ThemeData.dark(),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController controller = TextEditingController();
#override
void initState() {
super.initState();
controller.addListener(_printLatestValue);
}
void _printLatestValue() {
print('Second text field: ${controller.text}');
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: TextField(
controller: controller,
),
);
}
}
I want to use a variable, which i want to fill with firebase data.
In the Firebase section it fills it up with the correct data and print it correctly to log, but after that in the Scaffold its looks like it using the data in the starting declaration.
But why? It's one variable with two data? So at the end of the code in the Text('$masik') i want to use the firebase data, not the starting string.
What am i doing wrong?
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String masik = '';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firebase',
home: AddData(),
);
}
}
class AddData extends StatelessWidget {
#override
Widget build(BuildContext context) {
String doksi = 'valami más';
var ezlett;
String masik = 'minden';
String sajt = '';
final Stream<QuerySnapshot> collectionStream = FirebaseFirestore.instance.collection('zenek').snapshots();
FirebaseFirestore.instance
.collection('zenek')
.doc(doksi)
.get()
.then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
String ezegyszoveg = documentSnapshot.data().toString();
print('Document exists on the database $ezegyszoveg');
ezlett = ezegyszoveg.substring(9, ezegyszoveg.indexOf(','));
print(ezlett);
masik = ezegyszoveg.substring(ezegyszoveg.indexOf('text: ')+6, ezegyszoveg.indexOf('}'));
print(masik);
}
});
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.green,
title: const Text("próba"),
),
body:Row(
children: [
Text('$masik'),
],
)
);
}
}
Something like this example will work to update the UI when there is new data has been updated
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String masik = '';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firebase',
home: AddData(),
);
}
}
class AddData extends StatefulWidget {
#override
State<AddData> createState() => _AddDataState();
}
class _AddDataState extends State<AddData> {
String doksi = 'valami más';
var ezlett;
String masik = 'minden';
String sajt = '';
#override
void initState() {
super.initState();
updateTheUi();
}
void updateTheUi() {
final Stream<QuerySnapshot> collectionStream =
FirebaseFirestore.instance.collection('zenek').snapshots();
FirebaseFirestore.instance
.collection('zenek')
.doc(doksi)
.get()
.then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
String ezegyszoveg = documentSnapshot.data().toString();
ezlett = ezegyszoveg.substring(9, ezegyszoveg.indexOf(','));
masik = ezegyszoveg.substring(
ezegyszoveg.indexOf('text: ') + 6, ezegyszoveg.indexOf('}'));
setState(() {});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.green,
title: const Text("próba"),
),
body: Row(
children: [
Text('$masik'),
],
));
}
}
hey u r doing a silly mistake u have to use setState when u update your variable :
setState(){
masik = ezegyszoveg.substring(ezegyszoveg.indexOf('text: ')+6,ezegyszoveg.indexOf('}'));
} // this line put in setState in your code
I have a base class (IndicatorRenderDetails) and two derived classes (EmaIndicatorRenderDetails, SmaIndicatorRenderDetails) derived from a base class. Then, I have created typedef by using base class instance. My questions are that when I access the derived class instance in the function callback, I am unable to access its values and getting errors like below
The argument type 'Null Function(EmaIndicatorRenderDetails)' can't be assigned to the parameter type 'void Function(IndicatorRenderDetails)'
So, how can we avoid this error and access the derived class instance in the callback?
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ChartTestWidget(
technicalIndicators: <TechinicalIndicator>[
TechinicalIndicator(
onIndicatorRender: (IndicatorRenderDetails details) {
print(details.baseName);
}),
EmaTechinicalIndicator(
onIndicatorRender: (EmaIndicatorRenderDetails details) {
print(details.emaIndicatorName);
}),
SmaTechinicalIndicator(
onIndicatorRender: (SmaIndicatorRenderDetails details) {
print(details.smaIndicatorName);
})
],
child: Center(
child: Container(color: Colors.red, height: 100, width: 100))));
}
}
class ChartTestWidget extends SingleChildRenderObjectWidget {
const ChartTestWidget({Widget child, this.technicalIndicators})
: super(child: child);
//final EmployeeCallback employeeCallback;
final List<TechinicalIndicator> technicalIndicators;
#override
RenderProxyBox createRenderObject(BuildContext context) {
return ChartTestWidgetRenderProxyBox(this);
}
#override
void updateRenderObject(
BuildContext context, covariant RenderObject renderObject) {
super.updateRenderObject(context, renderObject);
}
}
class ChartTestWidgetRenderProxyBox extends RenderProxyBox {
ChartTestWidgetRenderProxyBox(this.testWidget, {RenderBox child})
: super(child);
final ChartTestWidget testWidget;
#override
void performLayout() {
if (child != null) {
child.layout(constraints, parentUsesSize: true);
size = child.size;
}
}
#override
void paint(PaintingContext context, Offset offset) {
if (testWidget.technicalIndicators != null &&
testWidget.technicalIndicators.isNotEmpty) {
for (final TechinicalIndicator technicalIndicator
in testWidget.technicalIndicators) {
if (technicalIndicator is EmaTechinicalIndicator) {
final EmaIndicatorRenderDetails emaIndicatorRenderDetails =
EmaIndicatorRenderDetails(
'emaTechnicalIndicator', 'technicalIndicator');
technicalIndicator.onIndicatorRender(emaIndicatorRenderDetails);
} else if (technicalIndicator is SmaTechinicalIndicator) {
final SmaIndicatorRenderDetails smaIndicatorRenderDetails =
SmaIndicatorRenderDetails(
'smaTechnicalIndicator', 'technicalIndicator');
technicalIndicator.onIndicatorRender(smaIndicatorRenderDetails);
} else if (technicalIndicator is TechinicalIndicator) {
final IndicatorRenderDetails indicatorRenderDetails =
IndicatorRenderDetails(baseName: 'technicalIndicator');
technicalIndicator.onIndicatorRender(indicatorRenderDetails);
}
}
}
super.paint(context, offset);
}
}
class TechinicalIndicator {
TechinicalIndicator({this.onIndicatorRender});
final IndicatorCallback onIndicatorRender;
}
class EmaTechinicalIndicator extends TechinicalIndicator {
EmaTechinicalIndicator({IndicatorCallback onIndicatorRender})
: super(onIndicatorRender: onIndicatorRender);
}
class SmaTechinicalIndicator extends TechinicalIndicator {
SmaTechinicalIndicator({IndicatorCallback onIndicatorRender})
: super(onIndicatorRender: onIndicatorRender);
}
class IndicatorRenderDetails {
IndicatorRenderDetails({this.baseName});
final String baseName;
}
class EmaIndicatorRenderDetails extends IndicatorRenderDetails {
EmaIndicatorRenderDetails(this.emaIndicatorName, String baseName)
: super(baseName: baseName);
final String emaIndicatorName;
}
class SmaIndicatorRenderDetails extends IndicatorRenderDetails {
SmaIndicatorRenderDetails(this.smaIndicatorName, String baseName)
: super(baseName: baseName);
final String smaIndicatorName;
}
typedef IndicatorCallback<T> = void Function(IndicatorRenderDetails details);
I have created following 2 streams.
Stream 1 - Periodic Stream which is calling an async function at a particular time.
Stream 2 - Function which listens on stream 1 and then create stream 2
I wanted to add logic such that if stream 1 length is more that 0 then only create stream 2. But I am getting length of stream 1 as always 0.
My Code is as follows. (It runs after hot reload)
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _counter = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyPage(),
);
}
}
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
StreamController<List<String>> _myStreamController =
StreamController<List<String>>();
int _counter = 0;
Stream<List<String>> _stream() {
Duration interval = Duration(milliseconds: 100);
Stream<List<String>> stream =
Stream<List<String>>.periodic(interval, temp2);
return stream;
}
Future temp() async {
List<String> a = [];
_counter++;
a.add(_counter.toString());
return a;
}
List<String> temp2(int value) {
List<String> _localMsg = List();
temp().then((a) {
print(a);
_localMsg = a;
});
return _localMsg;
}
#override
void initState() {
super.initState();
_stream().listen((ondata) {
print(ondata);
if (ondata.length > 0) _myStreamController.sink.add(ondata);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: StreamBuilder(
stream: _myStreamController.stream,
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(snapshot.data.toString());
} else {
return Text("waiting...");
}
},
),
),
),
);
}
}