Is there a Flutter equivalent to Bootstrap Scrollspy? - flutter

I am looking for a flutter package that is equivalent to that of Bootstrap’s Scrollspy:
https://getbootstrap.com/docs/4.0/components/scrollspy/
The intended functionality is to have a vertical scrollable list of items with a sticky horizontal scrollable “header/navbar menu” on top of it. When the user scrolls through the vertical list and reaches a new “section” this is reflected in the horizontal navbar by highlighting the “section name” in the navbar and scrolling to it if necessary. When the user presses on a section name in the horizontal navbar, it should scroll to the start of that section in the vertical list.
Ex:
Section1 !!!Section2!!! Section3 Section4
——————————————————————
(Section1 is not visible)
!!!Section2!!!
Item3
Item4
Section3
Item1
Item2
Section4
Item5
Item6

I think you can achieve this with the scrollable_positioned_list package made by Google Fuchsia Authors.
The ScrollablePositionedList provides a ItemPositionsListener:
_itemPositionsListener.itemPositions.addListener(() {
final positions = _itemPositionsListener.itemPositions.value;
setState(() {
_topItem = positions.isNotEmpty ? positions.first.index : null;
});
});
Full source code
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final _nbItems = 6;
final _itemHeight = 200.0;
final _itemPositionsListener = ItemPositionsListener.create();
int _topItem = 0;
#override
void initState() {
super.initState();
_itemPositionsListener.itemPositions.addListener(() {
final positions = _itemPositionsListener.itemPositions.value;
setState(() {
_topItem = positions.isNotEmpty ? positions.first.index : null;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: List.generate(
_nbItems,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.all(4.0),
decoration: _topItem == index
? BoxDecoration(
color: Colors.black26,
border: Border.all(color: Colors.black54),
)
: BoxDecoration(),
child: Text(
'S$index',
style: TextStyle(
fontWeight: _topItem == index
? FontWeight.bold
: FontWeight.normal,
),
),
),
),
),
),
Expanded(
child: ScrollablePositionedList.builder(
itemCount: _nbItems,
itemBuilder: (context, index) => SizedBox(
height: _itemHeight,
child: Card(
child: Text('Item $index'),
),
),
itemPositionsListener: _itemPositionsListener,
),
),
],
),
);
}
}

Related

How to change Text and Icon color depends on Background Image?

Anyone knows how to change icon and text color depending on the background color of the image or video?
The palette_generator package can help you find the most dominant color(s) in the image. You can use these color(s) to set the Text and Icon color.
Please check out the example code provided by the package author https://pub.dev/packages/palette_generator/example . The PaletteGenerator.fromImageProvider method can be used to get the color pallet from the image. You can use the following code from the example :
Future<void> _updatePaletteGenerator(Rect newRegion) async {
paletteGenerator = await PaletteGenerator.fromImageProvider(
widget.image,
size: widget.imageSize,
region: newRegion,
maximumColorCount: 20,
);
setState(() {});
}
....
Color dominantColor = paletteGenerator.dominantColor?.color;
....
Please see the entire working code below : (Add palette_generator: ^0.2.3 to your pubspec.yaml first)
import 'package:flutter/material.dart';
import 'package:palette_generator/palette_generator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Palette Generator',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Future _updateColors;
final List<PaletteColor> _colors = [];
int _currentIndex;
final List<String> _images = [
'https://picsum.photos/id/491/200/300',
'https://picsum.photos/id/400/200/300',
'https://picsum.photos/id/281/200/300'
];
#override
void initState() {
super.initState();
_currentIndex = 0;
_updateColors = _updatePalettes();
}
Future<bool> _updatePalettes() async {
for (final String image in _images) {
final PaletteGenerator generator =
await PaletteGenerator.fromImageProvider(NetworkImage(image));
_colors.add(generator.dominantColor != null
? generator.dominantColor
: PaletteColor(Colors.blue, 2));
}
setState(() {});
return true;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Color Palette Generator Demo'),
elevation: 0,
backgroundColor: _colors.isNotEmpty
? _colors[_currentIndex].color
: Theme.of(context).primaryColor,
),
body: FutureBuilder<bool>(
future: _updateColors,
builder: (context, snapshot) {
if (snapshot.data == true)
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: double.infinity,
height: 200,
color: _colors.isNotEmpty
? _colors[_currentIndex].color
: Colors.white,
child: PageView(
onPageChanged: (value) =>
setState(() => _currentIndex = value),
children: _images
.map((image) => Container(
padding: const EdgeInsets.all(16.0),
margin: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
image: DecorationImage(
image: NetworkImage(image),
fit: BoxFit.cover,
),
),
))
.toList(),
),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(32.0),
width: double.infinity,
decoration: BoxDecoration(
color: _colors.isNotEmpty
? _colors[_currentIndex].color
: Colors.white),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Color Palette",
style: TextStyle(
color: _colors.isNotEmpty
? _colors[_currentIndex].titleTextColor
: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 30.0,
),
),
const SizedBox(height: 10.0),
Icon(
Icons.ac_unit,
size: 100,
color: _colors.isNotEmpty
? _colors[_currentIndex].bodyTextColor
: Colors.black,
)
],
),
),
),
],
);
return const Center(child: CircularProgressIndicator());
},
),
);
}
}

Unable to open keyboard when checking MediaQuery of bottom insets in flutter

I'm trying to check if the keyboard is visible after tapping on the TextFormField by calling:
if (MediaQuery.of(context).viewInsets.bottom != 0) {
...
}
but as soon as I have this MediaQuery call in my code, the Keyboard doesn't even open anymore after tapping on the TextFormField...
Edited:
This is what happens when tapping on the TextFormField:
I added the code of the page which causes this faulty behavior:
class LearnPage extends StatefulWidget {
final int topicId;
final String topicName;
LearnPage(this.topicId, this.topicName);
#override
_LearnPageState createState() => _LearnPageState();
}
class _LearnPageState extends State<LearnPage> {
final mainCaardIndex = ValueNotifier<int>(0);
PageController _mainCaardController;
PageController _inputCaardController;
List<CaardM> caards;
List<PageM> mainCaardList = [];
List<List<PageM>> inputCaardList = [];
List<List<TextEditingController>> textControllers = [];
Future<void> async_init() async {
List<CaardM> caardList =
await DatabaseProviderCaard.db.getCaards(widget.topicId);
caards = caardList;
setState(() {});
}
bool _keyboardIsVisible() {
return !(MediaQuery.of(context).viewInsets.bottom == 0.0);
}
#override
void initState() {
async_init();
_mainCaardController = PageController();
_inputCaardController = PageController();
super.initState();
}
#override
void dispose() {
_mainCaardController.dispose();
_inputCaardController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue,
title: Center(
child: Text(
widget.topicName,
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
actions: [
!_keyboardIsVisible()
? IconButton(
icon: Icon(Icons.check_circle_outline),
tooltip: 'Validate',
onPressed: validate,
)
: IconButton(
icon: Icon(Icons.keyboard_hide),
onPressed: () {
FocusManager.instance.primaryFocus.unfocus();
},
),
],
),
body: Column(
children: [
Expanded(
flex: 3,
child: FutureBuilder(
future: getMainContent(),
builder: (context, AsyncSnapshot<int> snapshotMain) {
if (snapshotMain.connectionState == ConnectionState.done) {
return PageView.builder(
itemCount: snapshotMain.data,
controller: _mainCaardController,
onPageChanged: (position) {
mainCaardIndex.value = position;
mainCaardIndex.notifyListeners();
_inputCaardController.jumpToPage(0);
},
itemBuilder: (context, position) {
return LearnMainCaard(
mainCaardList[position].title,
mainCaardList[position].content,
);
},
);
} else {
return CircularProgressIndicator();
}
},
),
),
Expanded(
flex: 5,
child: FutureBuilder(
future: getInputContent(),
builder: (context, AsyncSnapshot<int> snapshotInput) {
if (snapshotInput.connectionState == ConnectionState.done) {
return ValueListenableBuilder(
valueListenable: mainCaardIndex,
builder: (context, value, _) {
return PageView.builder(
itemCount: snapshotInput.data,
controller: _inputCaardController,
itemBuilder: (context, position) {
return LearnInputCaard(
inputCaardList[mainCaardIndex.value][position].title,
textControllers[mainCaardIndex.value][position],
);
},
);
},
);
} else {
return CircularProgressIndicator();
}
},
),
),
],
),
);
}
Future<int> getMainContent() async {
List<PageM> caardPages;
mainCaardList.clear();
for (var i = 0; i < caards.length; i++) {
caardPages = await DatabaseProviderPage.db.getPages(caards[i].id);
if (caards[i].pageAmount > 1) {
mainCaardList.add(caardPages[0]);
}
}
return mainCaardList.length;
}
Future<int> getInputContent() async {
List<PageM> caardPages = [];
List<PageM> list = [];
inputCaardList.clear();
for (var i = 0; i < caards.length; i++) {
caardPages = await DatabaseProviderPage.db.getPages(caards[i].id);
if (caards[i].pageAmount > 1) {
addController(caards[i].pageAmount - 1);
list = [];
for (var i = 1; i < caardPages.length; i++) {
list.add(caardPages[i]);
}
inputCaardList.add(list);
}
}
return inputCaardList[mainCaardIndex.value].length;
}
void addController(int controllerAmount) {
List<TextEditingController> currentTextControllers = [];
print('addController called');
currentTextControllers.clear();
currentTextControllers = List.generate(
controllerAmount, (index) => TextEditingController()
);
textControllers.add(currentTextControllers);
}
And here the LearnInputCaard widget:
import 'package:flutter/material.dart';
class LearnInputCaard extends StatefulWidget {
final String title;
final TextEditingController textController;
LearnInputCaard(
this.title,
this.textController,
);
#override
_LearnInputCaardState createState() => _LearnInputCaardState();
}
class _LearnInputCaardState extends State<LearnInputCaard> {
#override
Widget build(BuildContext context) {
return Container(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
margin: EdgeInsets.all(20),
color: Colors.amberAccent.shade100,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Expanded(
flex: 1,
child: Text(
widget.title,
style: TextStyle(fontSize: 20),
),
),
Divider(color: Colors.black38,),
Expanded(
flex: 10,
child: Container(
padding: EdgeInsets.all(10.0),
child: TextFormField(
controller: widget.textController,
maxLines: 30,
decoration: InputDecoration(
hintText: "Enter content",
border: InputBorder.none,
),
),
),
)
],
),
),
),
);
}
}
you need to check MediaQuery.of(context).viewInsets.bottom == 0.0
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Keyboard Visibility Demo'),
);
}
}
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(
title: Text(widget.title),
),
body: Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_keyboardIsVisible()
? Text(
"Keyboard is visible",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.blue),
)
: RichText(
text: TextSpan(children: [
TextSpan(
text: "Keyboard is ",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.blue),
),
TextSpan(
text: "not ",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.red),
),
TextSpan(
text: "visible",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.blue),
)
]),
),
SizedBox(
height: 20,
),
Container(
width: 200.0,
child: TextField(
style: Theme.of(context).textTheme.display1,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
borderRadius: BorderRadius.circular(10.0),
),
),
),
)
],
),
));
}
bool _keyboardIsVisible() {
return !(MediaQuery.of(context).viewInsets.bottom == 0.0);
}
}
The problem is that you get the context from the parent widget.
If you call:
MediaQuery.of(context);
in the same widget where your forms are, you shouldn't get this behavior.
You need to define a GlobalKey<FormState> in your highest widget and pass this one down. Then it works. I defined it first in my SafeArea and therefore it failed and I had the same problem with the keyboard.
Here are some snippets of my code. I have a PageController and use two different forms on my two pages.
class OnboardingScaffold extends HookConsumerWidget {
OnboardingScaffold({Key? key}) : super(key: key);
// here you define your GlobalKeys
final _formKeyLogin = GlobalKey<FormState>();
final _formKeyApply = GlobalKey<FormState>();
#override
Widget build(BuildContext context, WidgetRef ref) {
final controller = usePageController();
bool isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
return Scaffold(
body: Container(
padding: !isKeyboard
? const EdgeInsets.only(bottom: 80)
: const EdgeInsets.only(bottom: 0),
child: PageView(
controller: controller,
children: [
// here you pass these keys into your child Widget
LoginSafeArea(
formKey: _formKeyLogin,
),
ApplySafeArea(
formKey: _formKeyApply,
),
],
),
),
bottomSheet: !isKeyboard
? Container(height: 80)
: Container(height: 0),
);
}
}
The child Widget should contain a Form Widget:
class LoginSafeArea extends HookConsumerWidget {
const LoginSafeArea({Key? key, required this.formKey}) : super(key: key);
final GlobalKey<FormState> formKey;
#override
Widget build(BuildContext context, WidgetRef ref) {
return SafeArea(
child: Center(
child: Form(
key: formKey,
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
const EmailFieldWidget(),
const SizedBox(height: 8.0),
const PasswordFieldWidget(),
const SizedBox(height: 16.0),
LoginButtonWidget(
formKey: formKey,
),
const SizedBox(height: 8.0),
],
),
),
),
),
);
}
}

How to implement a horizontal scroll which is controlled by bottom minus bar in flutter

I have to implement a horizontal scroll list in flutter.I could do that and have included the code below(The code is still to be modified but the base of the code is good enough to put in the pictures and other such details)
But the problem is the minus bar below the horizontal scroll.I don't know what feature in flutter allows to do that.I search many things but other than radio boxes,check boxes, switches,etc I am not able to find any details of it.Please have a look at the screenshot of the app ,I have indicated the minus bar control in red.Home screen,the minus bar indicated in red
The code I have written:
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black ,
body: Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 500,
child: ListView(
// This next line does the trick.
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: <Widget>[
Container(
width:400 ,
color: Colors.red,
),
Container(
width: 400.0,
color: Colors.blue,
),
Container(
width: 400.0,
color: Colors.green,
),
],
),
)
);
}
}
What you want to look for is not ListView but PageView here is a small code sample to try in DartPad and see how you could make your layout.
Basically I am using a PageController to change the current page by taping on certain widgets.
Code
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(body: MyWidget()),
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
final _items = [Colors.red, Colors.blue, Colors.yellow];
final _pageController = PageController();
int _currentPageNotifier = 0;
final double _indicatorWidth = 30;
Widget _buildPageView() {
return PageView.builder(
controller: _pageController,
itemCount: _items.length,
itemBuilder: (context, index) => Center(
child: FlutterLogo(
colors: _items[index],
size: 50,
),
),
onPageChanged: (int index) =>
setState(() => _currentPageNotifier = index),
);
}
Widget _buildIndicator() {
List<Widget> itemWidgets = [];
for (int index = 0; index < _items.length; index++) {
itemWidgets.add(GestureDetector(
onTap: () => _pageController.animateToPage(
index,
duration: Duration(milliseconds: 300),
curve: Curves.ease,
),
child: Container(
decoration: BoxDecoration(
color: _currentPageNotifier == index
? Colors.green
: Colors.grey,
borderRadius: BorderRadius.circular(9),
),
margin: EdgeInsets.only(right: 10),
width: _indicatorWidth,
height: 8,
),
));
}
return Positioned(
bottom: MediaQuery.of(context).size.height / 2 - 50,
left: MediaQuery.of(context).size.width / 2 -
_items.length * _indicatorWidth +
_items.length * 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: itemWidgets,
),
);
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
_buildPageView(),
_buildIndicator(),
],
);
}
}

Wrap middle element to new row if needed?

I have a navigation bar at the bottom of a multi-page form, with buttons to go back or forward, and an indicator for the current page.
Right now, I have the indicator place in a Row above another Row that contains the buttons, like this:
This works, and it will work even on small display sizes. However, I would rather have the indicators placed on the same row as the buttons if there is enough space, like this (except that the indicator is not centered):
The problem is, this could be too wide for some devices, especially if there are more than just a few pages. In that case, I would like either the page indicator or the buttons to "wrap" to a new row, as in the current design.
It would be easy to put everything in a Wrap, but that will make the NEXT-button wrap instead of the page indicator, since that is the last element.
Is there an easy way to make the middle element wrap onto a new row if needed? Or does one have to resort to the black magic of manually calculating sizes and creating two different layouts?
The easiest solution is to add invisible wrap to calculate the height.
import 'package:flutter/material.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: Scaffold(
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentPageIndex = 1;
int pageCount = 8;
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
currentPageIndex.toString(),
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
RaisedButton(
child: Text('+1 page'),
onPressed: () => setState(() => ++pageCount),
),
SizedBox(
width: 10,
),
RaisedButton(
child: Text('-1 page'),
onPressed: () => setState(() => --pageCount),
),
],
)
],
),
),
),
Container(
child: _BottomNavigation(
onPrev: () => setState(() => --currentPageIndex),
onNext: () => setState(() => ++currentPageIndex),
currentCount: currentPageIndex,
totalCount: pageCount,
),
),
],
);
}
}
class _BottomNavigation extends StatelessWidget {
const _BottomNavigation({
Key key,
#required this.totalCount,
#required this.currentCount,
#required this.onNext,
#required this.onPrev,
}) : assert(totalCount != null),
assert(currentCount != null),
assert(onNext != null),
assert(onPrev != null),
super(key: key);
final void Function() onPrev;
final void Function() onNext;
final int totalCount;
final int currentCount;
#override
Widget build(BuildContext context) {
return Stack(
children: [
buildHelper(),
buildIndicatorBar(),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_button(
'<< PREIOUS',
onPrev,
isVisible: currentCount > 1,
),
_button(
'NEXT >>',
onNext,
isVisible: currentCount < totalCount,
),
],
),
),
],
);
}
Wrap buildHelper() {
return Wrap(
children: List.generate(
totalCount,
(index) {
return Container(
width: index == 0 ? 250 : 15,
height: 20,
);
},
),
);
}
Row buildIndicatorBar() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(totalCount, (index) {
var isLast = totalCount != index + 1;
var isCurrent = currentCount == index + 1;
return Container(
height: isCurrent ? 20 : 10,
width: isCurrent ? 20 : 10,
margin: EdgeInsets.only(right: isLast ? 10 : 0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isCurrent ? Colors.blueAccent : null,
border: Border.all(
color: Colors.blueAccent,
),
),
);
}),
);
}
Widget _button(String text, void Function() onPress, {bool isVisible}) {
return Visibility(
visible: isVisible,
child: GestureDetector(
onTap: onPress,
child: Text(text),
),
);
}
}

How to add custom widget when button is pressed

I used a couple other threads to create an app where you type in some text in a textfield and when you press the button a default container is added to a list with the text in one of the fields. However when I type the text and add the widget the text is changed for all entries instead of just for the one that was added. This is my code:
import 'dart:core';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int count = 0;
TextEditingController noteSend = TextEditingController();
#override
Widget build(BuildContext context) {
List<Widget> children = new List.generate(
count,
(int i) => new InputWidget(
i,
noteRec: noteSend.text,
));
return new Scaffold(
appBar: new AppBar(title: new Text('some title')),
body: Column(
children: <Widget>[
Container(
child: TextField(
controller: noteSend,
),
color: Colors.lightBlueAccent,
width: 150,
height: 50,
),
Expanded(
child: ListView(
children: children,
scrollDirection: Axis.vertical,
),
),
],
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: () {
setState(() {
count = count + 1;
});
},
));
}
}
class InputWidget extends StatefulWidget {
final int index;
final String noteRec;
InputWidget(this.index, {Key key, this.noteRec}) : super(key: key);
#override
_InputWidgetState createState() => _InputWidgetState();
}
class _InputWidgetState extends State<InputWidget> {
#override
Widget build(BuildContext context) {
return new Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.image,
size: 75,
)
],
),
Container(
margin: EdgeInsets.only(left: 80, right: 30),
child: Column(
children: <Widget>[
Text('Note'),
],
),
),
Column(
children: <Widget>[
Text("${widget.noteRec}"),
],
),
],
),
);
}
}
How can I make the Text different with every entry?
List<Widget> children = new List.generate(
count,
(int i) => new InputWidget(
i,
noteRec: noteSend.text,
));
In this code, you set the input text for all the elements in children. It's the reason all the entries are changed to the same text. You can save the text to a list of the string when you press the save button and call it in List.generate:
List<Widget> children = new List.generate(
count,
(int i) => new InputWidget(
i,
noteRec: listString[i],
));
Try this code
Container(
height: 200,
child: Column(
children: <Widget>[
Expanded(
child: buildGridView(),
)
],
),
),
Then call the buildGridView that will return Widgets
Widget buildGridView() {
return Text('text here'); // your future widget
}