How to add custom widget when button is pressed - flutter

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
}

Related

Flutter - Row added -> change the text of a container

I'm quite inexperienced with flutter and have created this script.
When you tap on the red container you create a Row of buttons,
I would like when I click on a button in the Row -> the text of the blue container becomes the same as the text contained in the tapped button
Anyone know how I can do?
Thank you :)
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Chat(),
);
}
}
class Chat extends StatefulWidget {
const Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
String text = 'Henlo i am Gabriele!';
List<Container> OutputList = [];
void tool(String text) async {
List ListText = text.split(' ');
for (var i in ListText) {
OutputList.add(
Container(
child: GestureDetector(
onTap: () {},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Container(
color: Colors.orange,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(i),
),
),
),
),
),
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
GestureDetector(
onTap: () {
setState(() {
tool(text);
print(OutputList);
});
},
child: Container(
width: 150.0,
height: 50.0,
color: Colors.red,
child: Center(child: Text('START ->')),
),
),
SizedBox(height: 50.0),
Row(
children: OutputList,
),
SizedBox(height: 50.0),
Container(
color: Colors.blue,
width: 200.0,
height: 50.0,
child: Text(''),
),
],
),
),
);
}
}
Yes you can add a few line of code check here i try to solve.
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
void main() => runApp(mainApp());
class mainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Chat(),
);
}
}
class Chat extends StatefulWidget {
const Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
String text = 'Henlo i am Gabriele!';
//step 1 create variable
String newGeneratedText = "";
List<Container> OutputList = [];
void tool(String text) async {
List ListText = text.split(' ');
for (var i in ListText) {
OutputList.add(
Container(
child: GestureDetector(
onTap: () {
//add logic here to concatinate values
setState(() {
newGeneratedText = newGeneratedText + " " + i;//added " " for one space
});
},
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Container(
color: Colors.orange,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(i),
),
),
),
),
),
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
GestureDetector(
onTap: () {
setState(() {
tool(text);
print(OutputList);
});
},
child: Container(
width: 150.0,
height: 50.0,
color: Colors.red,
child: Center(child: Text('START ->')),
),
),
SizedBox(height: 50.0),
Wrap( // added for fixing more values and solve overflow exceptions error
children: OutputList,
),
SizedBox(height: 50.0),
Container(
color: Colors.blue,
width: 200.0,
height: 50.0,
child: Text(newGeneratedText), //final print values
),
],
),
),
);
}
}

How to make Column scrollable when overflowed but use expanded otherwise

I am trying to achieve an effect where there is expandable content on the top end of a sidebar, and other links on the bottom of the sidebar. When the content on the top expands to the point it needs to scroll, the bottom links should scroll in the same view.
Here is an example of what I am trying to do, except that it does not scroll. If I wrap a scrollable view around the column, that won't work with the spacer or expanded that is needed to keep the bottom links on bottom:
import 'package:flutter/material.dart';
const 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: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
State<MyWidget> createState() {
return MyWidgetState();
}
}
class MyWidgetState extends State<MyWidget> {
List<int> items = [1];
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
setState(() {
items.add(items.last + 1);
});
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
if (items.length != 1) items.removeLast();
});
},
),
],
),
for (final item in items)
MyAnimatedWidget(
child: SizedBox(
height: 200,
child: Center(
child: Text('Top content item $item'),
),
),
),
Spacer(),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all()),
height: 200,
child: Text('Bottom content'),
)
],
);
}
}
class MyAnimatedWidget extends StatefulWidget {
final Widget? child;
const MyAnimatedWidget({this.child, Key? key}) : super(key: key);
#override
State<MyAnimatedWidget> createState() {
return MyAnimatedWidgetState();
}
}
class MyAnimatedWidgetState extends State<MyAnimatedWidget>
with SingleTickerProviderStateMixin {
late AnimationController controller;
#override
initState() {
controller = AnimationController(
value: 0, duration: const Duration(seconds: 1), vsync: this);
controller.animateTo(1, curve: Curves.linear);
super.initState();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, child) {
return SizedBox(height: 200 * controller.value, child: widget.child);
});
}
}
I have tried using a global key to get the size of the spacer and detect after rebuilds whether the spacer has been sized to 0, and if so, re-build the entire widget as a list view (without the spacer) instead of a column. You also need to listen in that case for if the size shrinks and it needs to become a column again, it seemed to make the performance noticeably worse, it was tricky to save the state when switching between column/listview, and it seemed not the best way to solve the problem.
Any ideas?
Try implementing this solution I've just created without the animation you have. Is a scrollable area at the top and a persistent footer.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("My AppBar"),
),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
// Your scrollable widgets here
Container(
height: 100,
color: Colors.green,
),
Container(
height: 100,
color: Colors.blue,
),
Container(
height: 100,
color: Colors.red,
),
],
),
),
),
Container(
child: Text(
'Your footer',
),
color: Colors.blueGrey,
height: 200,
width: double.infinity,
)
],
),
),
),
);
}
}

Is there a Flutter equivalent to Bootstrap Scrollspy?

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,
),
),
],
),
);
}
}

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),
),
);
}
}

Flutter ListView/ListTiles are not rendering on the page

I am new to Flutter/Dart but I am trying to incorporate a ListView into a project that I am working on but I cannot get it to work. I have tried it at least 12 different ways and it is still not working. I know the issue has something to do with the way I am sizing (or not sizing) the ListView/ListTiles. I have tried adding heights to SizedBoxes, heights to Containers, widths to columns, Expanded, Flexible etc. Nothing has worked. I am not posting the error messages because with all of the solutions I have tried they have all essentially been related to either the height or width of the ListView/ListTile exceeding the limitations of the screen. Below are the latest code snippet I have tried. I know there are several topics on SO that have addressed this but I have not been able to get any of them to work. My ListView should only contain 3 tiles so perhaps a ListView.Builder would be better. I am open to any suggestions or advice. Thanks in advance for the help!
class _HotelFormState extends State<HotelForm> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hotel Form'),
),
body: Column(
children: <Widget>[
SizedBox(height: 20.0),
Row(
children: <Widget>[
TripDates(),
],
),
SizedBox(height: 20.0),
Column(
children: <Widget>[
RoomCounts(),
],
),
],
),
);
}
}
RoomCounts Class
class RoomCounts extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
height: 100.0,
child: new ListView(
children: new List.generate(3, (i) => new ListTileItem(title: "$i",)),
),
),
);
}
}
ListTile Class
class _ListTileItemState extends State<ListTileItem> {
//Some lists are here
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Flexible(
child: ListTile(
leading: Icon(widget.icons),
title: new Text(widget.title),
trailing: new Row(
children: <Widget>[
_itemCount != 0
? new IconButton(icon: new Icon(Icons.remove), onPressed: () => setState(() => _itemCount--),)
: new Container(),
new Text(_itemCount.toString()),
new IconButton(icon: new Icon(Icons.add), onPressed: () => setState(() => _itemCount++))
],
),
),
),
],
);
}
}
You can copy paste run full code below
You do not need Scaffold in RoomCounts
You do not need Column in _ListTileItemState
You need SizedBox in trailing of ListTile
working demo
full code
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: HotelForm(),
);
}
}
class HotelForm extends StatefulWidget {
#override
_HotelFormState createState() => _HotelFormState();
}
class _HotelFormState extends State<HotelForm> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hotel Form'),
),
body: Column(
children: <Widget>[
SizedBox(height: 20.0),
/*Row(
children: <Widget>[
TripDates(),
],
),*/
SizedBox(height: 20.0),
Column(
children: <Widget>[
RoomCounts(),
],
),
],
),
);
}
}
class RoomCounts extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 100.0,
child: ListView(
children: List.generate(
3,
(i) => ListTileItem(
title: "$i",
)),
),
);
}
}
class ListTileItem extends StatefulWidget {
final String title;
final IconData icons;
ListTileItem({this.title, this.icons});
#override
_ListTileItemState createState() => _ListTileItemState();
}
class _ListTileItemState extends State<ListTileItem> {
int _itemCount = 0;
#override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(widget.icons),
title: Text(widget.title),
trailing: SizedBox(
width: 200,
child: Row(
children: <Widget>[
_itemCount != 0
? IconButton(
icon: Icon(Icons.remove),
onPressed: () => setState(() => _itemCount--),
)
: Container(),
Text(_itemCount.toString()),
IconButton(
icon: Icon(Icons.add),
onPressed: () => setState(() => _itemCount++))
],
),
),
);
}
}