how to draw a line with two point in it in flutter - flutter

I have two dropdown button that represt time (0-23) and the user can choose a time range for the light to be on. I want to represent the choosen times by a line like below where the the red circles move when they choose different time. it does not need to be circle, anything just to represent the range of time.
anyone have an idea or comments on that?

Use RangeSlider
One option is to use the RangeSlider in Flutter, to select an range of two values.
One caveat of the solution is that the range values are only visible while moving the thumb-selectors. Albeit you could use the callback function in the example to show the selected range elsewhere.
Example:
import 'package:flutter/material.dart';
// This StatefulWidget uses the Material RangeSlider and provides a
// callback for the updated range.
class SliderExample extends StatefulWidget {
const SliderExample({
Key? key,
required this.onRangeSelected,
required this.values
}) : super(key: key);
final RangeValues values;
final Function(RangeValues) onRangeSelected;
#override
State<SliderExample> createState() => _SliderExampleState();
}
class _SliderExampleState extends State<SliderExample> {
late RangeValues selectedRange;
#override
void initState() {
super.initState();
selectedRange = widget.values;
}
#override
Widget build(BuildContext context) {
return RangeSlider(
values: selectedRange,
onChanged: (range) {
setState(() {
selectedRange = range;
});
widget.onRangeSelected(range);
},
min: widget.values.start,
max: widget.values.end,
divisions: 24,
labels: RangeLabels("${selectedRange.start.round()}", "${selectedRange.end.round()}"),
);
}
}
// Using the SliderExample widget we just defined:
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SliderExample(
values: const RangeValues(0, 23),
onRangeSelected: (range) => print("${range.start} - ${range.end}"),
),
],
),
),
);
}
}
main() => runApp(const App());
Other approaches
Time Picker
However, you might want to consider using a time-picker instead if you want more fine-tuned control for the time: https://material.io/components/time-pickers/flutter#using-time-pickers

You can use RangeSlider Widget
https://api.flutter.dev/flutter/material/RangeSlider-class.html

Related

"RangeError (index): Index out of range: no indices are valid: 0" when trying to get a barcode

In Flutter I actually write a smartphone app for my company. There is also a barcode reader to legitimize customers to enter the store.
The problem is that whenever I want to convert a 13 number string into a barcode I get the error shown above.
For first time using the App the customer types his number into a TextField. The number (originally a String) will be stored in a private variable _number (also from type String) for further processing.
Even if I use my function
convert2barcode('1111111111116')
the barcode is shown correctly, but not for
convert2barcode(_number)
I have no idea why. If I write
print(_number)
I get the correct result (e.g. '1111111111116').
Hope you can help. Tell me if you need more code information.
Best regards.
EDIT
I wrote a more simple example to understand what I mean.
I've a TextField where a numeric String will be converted into a barcode at submitting.
import 'package:flutter/material.dart';
import 'barcode.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: GUI(),
);
}
}
class GUI extends StatefulWidget {
GUI({Key? key}) : super(key: key);
#override
State<GUI> createState() => _GUI();
}
class _GUI extends State<GUI> {
bool _isVisible = false;
String numer = "";
void showWidget() {
setState(() {
_isVisible = !_isVisible;
});
}
#override
Widget build(BuildContext contet) {
return Scaffold(
body: Visibility(
child: Row(
children: /*[
Text(_numer.runtimeType.toString())
]*/
Barcode.convert2Barcode(numer),
),
visible: _isVisible,
replacement: Column(
children: [
TextField(
onSubmitted: (value) {
numer = value;
showWidget();
},
),
],
),
),
);
}
}
This is the code which caused the exception:
Barcode.convert2Barcode(numer),
If I run the code I'll get the error shown in the headline.
Only If I write
convert2barcode('1111111111116'),
the barcode will be shown correctly.
I have output the type of the variable with runtimeType for both ('1111111111116' and _numer). It's always the same (String). Even if I make something like this
_numer = '1111111111116';
print(_numer);
I will get the correct result.
I have really no idea what this exception cause.
When TextField's onSubmit is not called, the number is empty. That's the reason you get the error.
Replace
Barcode.convert2Barcode(numer),
with
if (number.isNotEmpty)
Barcode.convert2Barcode(numer),

flutter slider not updating widget variables

am playing around with the slider widget on flutter, and I can't figure out why it does not update certain values in a different widget, example code is shown below;
When i move the slider, it has no issues moving, but the value i'm trying to update on the other widget does not update even though the onchanged is updating the variable passed through in a set state accordingly.
any help would be greatly appreciated!
Scaffold Code
class TestPage extends StatelessWidget {
static const id = "test_page";
#override
Widget build(BuildContext context) {
double testValue = 0;
return Scaffold(
body: Column(
children: [
Text("Hello World"),
TestBoxNumber(
numberDisplay: testValue,
),
TestSlider(testValue: testValue),
],
),
);
}
}
Slider Code
class TestSlider extends StatefulWidget {
double testValue;
TestSlider({required this.testValue});
#override
_TestSliderState createState() => _TestSliderState();
}
class _TestSliderState extends State<TestSlider> {
#override
Widget build(BuildContext context) {
return Slider(
activeColor: themeData.primaryColorLight,
value: widget.testValue,
min: 0,
max: 100,
divisions: 100,
label: widget.testValue.round().toString(),
onChanged: (double value) {
setState(() {
widget.testValue = value;
});
},
);
}
}
Different Widget Code
class TestBoxNumber extends StatefulWidget {
final double numberDisplay;
const TestBoxNumber({required this.numberDisplay});
#override
_TestBoxNumberState createState() => _TestBoxNumberState();
}
class _TestBoxNumberState extends State<TestBoxNumber> {
#override
Widget build(BuildContext context) {
return Container(
child: Text(widget.numberDisplay.toString()),
);
}
}
The problem is that you are constructing TestBoxNumber widget in such a way that value (testValue) will always be the same (testValue is never returned out of the TestSlider widget).
How to overcome this issue?
You can make your TestPage a StatefullWidget. Then create callback from TestSlider, so when you change value in TestSlider you will call some function in TestPage (with setState in it, causing re-rendering your page).
Or if you don't want your whole TestPage widget to be Statefull (if, let's say, you predict a lot of other static widgets in it and you don't want them to be re-rendered because you just moved a slider), you can create wrapper Statefull widget and put both TestSlider and TestBoxNumber widgets in it. This is more flexible approach, imho.
Here is small scheme of what I mean by wrapping two widgets in another one:
UPD: btw, there is no point in making TestBoxText a statefull widget if it's only purpose is to display a text and you pass it's value through the constructor.

How to set a variable value in a widget and in another widget?

I'm trying to set a variable value (number, in the code below) that exists in FirstWidget, from SecondWidget. And notify both widgets so the number will be updated in the two widgets.
class FirstWidget extends StatefulWidget {
#override
_FirstWidgetState createState() => _FirstWidgetState();
}
class _FirstWidgetState extends State<FirstWidget> {
int number = 0;
#override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'$number',
),
SecondWidget(),
Text(
'$number',
)
],
);
}
}
class SecondWidget extends StatefulWidget {
#override
_SecondWidgetState createState() => _SecondWidgetState();
}
class _SecondWidgetState extends State<SecondWidget> {
#override
Widget build(BuildContext context) {
return TextButton(
child: Text('The number is $number. Press to increase the number'),
onPressed: () {
setState(() {
number++;
});
},
);
}
}
(I know that that code gives an error, but the main idea was to give you the problem I want to solve).
The output I want it to be shown:
before pressing the button -
0
The number is 0. Press to increase the number
0
after pressing the button -
1
The number is 1. Press to increase the number
1
So I would be happy if you can help solving this.
Thanks.
There are many approaches to get the result you are looking for, this one is using ValueNotifier in order to change the value of number
Here is an example based on your code:
https://dartpad.dev/b6409e10de32b280b8938aa75364fa7b
We can use another State Management like Provider or Cubit, and we will get the same result.
Another way is to pass a function as a param in the second widget and execute that function when button is pressed

I was told that 25th line of code contains an issue where setState() with random color being used. Help identify an issue

Original task sounded like:
The application should: display the text "Hey there" in the middle of
the screen and after tapping anywhere on the screen a background color
should be changed to a random color. You can also add any other
feature to the app - that adds bonus points Please do not use any
external libraries for color generation
My solution (GitHub):
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: RandomBackgroundColorWidget(),
);
}
}
class RandomBackgroundColorWidget extends StatefulWidget {
#override
_RandomBackgroundColorWidget createState() => _RandomBackgroundColorWidget();
}
class _RandomBackgroundColorWidget extends State<RandomBackgroundColorWidget> {
int _colorIndex = 0xFF42A5F5;
void _randomColorIndexGenerator() {
final _rng = new Random();
setState(() => {_colorIndex = (_rng.nextInt(0xFFFFFF) + 0xFF000000)});
}
#override
Widget build(BuildContext context) {
return Stack(children: [
Material(
color: Color(_colorIndex),
child: Center(
child: Text("Hey there"),
),
),
GestureDetector(
onTap: () => _randomColorIndexGenerator(),
),
]);
}
}
While reviewing my test task interviewer said that 25th line of code contains an issue.
setState(() => {_colorIndex = (_rng.nextInt(0xFFFFFF) + 0xFF000000)});
And he commented:
"It is working in a way that is not intended by you."
Help to identify an issue in 25th line of code.
You are accidentally combining the two ways to declare a function in Dart: the arrow operator => and curly braces {}.
Line 25 should be:
setState(() => _colorIndex = _rng.nextInt(0xFFFFFF) + 0xFF000000);
with no extra curly braces.
The issue is a syntax error. When using setState() =>, you dont need the {}
setState(() {_colorIndex = (_rng.nextInt(0xFFFFFF) + 0xFF000000)});
or
setState(() => _colorIndex = (_rng.nextInt(0xFFFFFF) + 0xFF000000));
I couldn't find the error you mention, however I recommend that you always use init state when assigning default values.
Here other way
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: RandomBackgroundColorWidget(),
);
}
}
class RandomBackgroundColorWidget extends StatefulWidget {
#override
_RandomBackgroundColorWidget createState() => _RandomBackgroundColorWidget();
}
class _RandomBackgroundColorWidget extends State<RandomBackgroundColorWidget> {
Color _color;
#override
void initState() {
_color = Colors.white;
super.initState();
}
void getrandomColor() {
setState(() {
_color = Colors.primaries[Random().nextInt(Colors.primaries.length)];
});
}
#override
Widget build(BuildContext context) {
return Stack(children: [
Material(
color: _color,
child: Center(
child: Text("Hey there"),
),
),
GestureDetector(
onTap: getrandomColor,
),
]);
}
}
Issue is in nextInt function.
Flutter accepts color codes for generation up to 0xFFFFFFFF, where first pair of numbers is needed for opacity level and other pairs needed for RGB levels
nextInt function generates random number in range up to, but not including, passed number. For example, nextInt(3) will generate randomly 0,1 or 2, but not 3.
So original app was generating all random colors (from 0x0 to 0xFFFFFE) except last one - 0xFFFFFF
Therefore, 25th line should look like this in order to generate every possible color.
setState(() => _colorIndex = (_rng.nextInt(0x1000000) + 0xFF000000));

How can I pass dynamic data from widget to widget?

Let me preface this by saying I am brand new to flutter/dart, and also not a super experienced programmer.
I'm trying to acquaint myself with flutter's framework and tools, and I'm trying to just expand upon the basic counter app that flutter creates on project generation. My goal is to have the app keep track of when the counter is 'reset', keep the time and count that the counter was at, and then display that data in a table on another screen.
Here's what I have so far:
I've made a class to keep track of the data:
class CounterRecord {
int _counter; //Holds the value the counter was at on reset
DateTime _resetTime; //Holds the time when the counter was reset
CounterRecord(int _count){
_counter = _count;
_resetTime = DateTime.now();
}
int getCount() => _counter; //fetch method for count
DateTime getTime() => _resetTime; //Fetch method for resettime
}
Here's the main class/home page:
import 'package:counter_app/clickerScreen.dart';
import 'package:counter_app/dataScreen.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
final clickerKey = new GlobalKey<ClickerScreenState>();
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.deepOrange,
accentColor: Colors.grey,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home'),
);
}
}
class MyHomePage extends StatefulWidget {
//Enables the passing in of the title, clicker screen instance, and datacreen isntance, respectively,
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//We don't want a brand new clickerScreen every time, so I'm keeping it up here.
ClickerScreen clickerScreen = ClickerScreen(clickerKey: clickerKey); //Creates a new clickerScreen - the key points to it too.
#override
Widget build(BuildContext context) {
//Creates an instance (State?) of clickerScreen for the first tab
return DefaultTabController( //A wrapper that helps manage the tab states
length: 2, //Currently there are only two options for screens
child: Scaffold(
appBar: AppBar( //This represnts the bar up at the top
title: Text(widget.title),
bottom: TabBar(
tabs: [
//These are the icons for the two tabs we're using
//The order of these is important: It goes in the same order as TabBarView below
Tab(icon: Icon(Icons.home)),
Tab(icon: Icon(Icons.directions_run)),
],
)
),
body: TabBarView(
children: [
clickerScreen,
DataScreen( //this DataScreen will be built every time based on the new data from clickerScreen
data: clickerKey.currentState.getRecords(),
),
],
),
),
);
}
}
class CounterRecord {
int _counter; //Holds the value the counter was at on reset
DateTime _resetTime; //Holds the time when the counter was reset
CounterRecord(int _count){
_counter = _count;
_resetTime = DateTime.now();
}
int getCount() => _counter; //fetch method for count
DateTime getTime() => _resetTime; //Fetch method for resettime
}
Here's the important part of my clickerScreen file:
class ClickerScreen extends StatefulWidget {
ClickerScreen({Key clickerKey}) : super(key: clickerKey);
#override
ClickerScreenState createState(){
return ClickerScreenState();
}
}
class ClickerScreenState extends State<ClickerScreen> {
int _counter = 0;
List<CounterRecord> records;
/* All three of these functions do very similar things, modify the counter value. */
void _resetCounter(){
setState(() {
records.add(CounterRecord(_counter));
_counter = 0;
});
}
List<CounterRecord> getRecords(){
return records;
}
There is a build method in clickerScreen that just displays buttons and text. I'm not assigning the key in there, as it just returns a Center widget, but I've read some things that suggest maybe I should be.
And here is my dataScreen file:
import 'package:flutter/material.dart';
import 'main.dart';
class DataScreen extends StatefulWidget{
//Enables the passing in of the instance of the clicker screen instance
DataScreen({Key key, #required this.data}) : super(key: key);
final List<CounterRecord> data;
#override
_DataScreenState createState(){
return _DataScreenState();
}
}
class _DataScreenState extends State<DataScreen>{
#override
Widget build(BuildContext context) {
return Text(widget.data.toString());
}
}
I know that it the displaying won't actually look like it's supposed to, as I'm just sending it toString(), but I want to make sure I can pass the data in before I start messing around with that.
When I run this, I get a NoSuchMethod error on getRecords(), receiver: null. I've also tried to call createState() on the ClickerScreen widget, as a last-ditch attempt.
Any advice?
(I've pasted the entire clickerScreen file here (https://pastebin.com/j6Y8M8F3) since I didn't want to make this post any longer than it already is.)
If you have two widgets depending on the same state you have to use something called "lifting state up". That means that the state is part of the closest widget that has both other widgets as children. In your case that would be the MyHomePage Widget that holds the CounterRecord List. It passes the list through the constructer to the DataScreen, and passes the onReset callback to the ClickerScreen.
MyHomePage:
class MyHomePage extends StatefulWidget {
//Enables the passing in of the title, clicker screen instance, and datacreen isntance, respectively,
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<CounterRecord> counterRecord = []; //this is the lifted up state
onReset(int count) {
setState(() {
counterRecord.add(CounterRecord(count));
});
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
//A wrapper that helps manage the tab states
length: 2, //Currently there are only two options for screens
child: Scaffold(
appBar: AppBar(
//This represnts the bar up at the top
title: Text(widget.title),
bottom: TabBar(
tabs: [
//These are the icons for the two tabs we're using
//The order of these is important: It goes in the same order as TabBarView below
Tab(icon: Icon(Icons.home)),
Tab(icon: Icon(Icons.directions_run)),
],
)),
body: TabBarView(
children: [
ClickerScreen(onReset: onReset),
DataScreen(
data: counterRecord, //pass the record data to the datascreen
),
],
),
),
);
}
}
ClickerScreen:
class ClickerScreen extends StatefulWidget {
final Function(int) onReset;
ClickerScreen({Key clickerKey, this.onReset}) : super(key: clickerKey);
#override
ClickerScreenState createState() {
return ClickerScreenState();
}
}
class ClickerScreenState extends State<ClickerScreen> {
int _counter = 0;
/* All three of these functions do very similar things, modify the counter value. */
void _resetCounter() {
widget.onReset(_counter); //call the onReset callback with the counter
setState(() {
_counter = 0;
});
}
#override
Widget build(BuildContext context) {
....
}
}
DataScreen (can be Stateless, since state is in its parent)
class DataScreen extends StatelessWidget{
//Enables the passing in of the instance of the clicker screen instance
DataScreen({Key key, #required this.data}) : super(key: key);
final List<CounterRecord> data;
#override
Widget build(BuildContext context) {
return Text(widget.data.toString());
}
}
Using this simple approach can get very annoying fast, and needs lot of changes when you move a widget in the widget tree. Thats why advanced state management like Provider with ChangeNotifier or Bloc exist.
Here is a good read on this matter::
https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
I followed Leo Letto's advice and instead used an InheritedWidget placed at the very top that held a list of records.