I have the following widget tree:
The ListView has scrollDirection: Axis.horizontal and 2 children. The Column has crossAxisAlignment: CrossAxisAlignment.center with 3 children. The 2nd child is significantly wider than the 1st and 3rd hence it determines the width of the column. How can I make the 1st widget in the column left aligned? Currently all three widgets are centered horizontally as per the crossAxisAlignment of the Column.
Here's the layout of the column:
As expected all three children of the Column get positioned in the center of it. I need to make the first one left aligned.
My code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(
left: 10,
right: 10,
),
child: _composeCard(),
);
}),
),
),
);
}
Widget _composeCard() {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
_composeShadow(dy: 2, blur: 8),
_composeShadow(dy: 0, blur: 1),
],
),
child: Material(
clipBehavior: Clip.antiAlias,
child: InkWell(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Text("Header"), // I want to push this widget to the left
SizedBox(height: 20),
Text("Body: Lorem ipsum dolor sit amet"),
SizedBox(height: 20),
Text("Footer"),
],
),
),
),
),
)),
);
}
BoxShadow _composeShadow({
required double dy,
required double blur,
double spread = 0,
}) {
return BoxShadow(
color: const Color(0xFFDBDBDB),
offset: Offset(0, dy),
spreadRadius: spread,
blurRadius: blur,
);
}
}
Thank you!
I modified your code to work.
You have to set a width for the item extend in your list, then you can use a row.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
itemExtent: 300,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(
left: 10,
right: 10,
),
child: _composeCard(),
);
}),
),
),
);
}
Widget _composeCard() {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
_composeShadow(dy: 2, blur: 8),
_composeShadow(dy: 0, blur: 1),
],
),
child: Material(
clipBehavior: Clip.antiAlias,
child: InkWell(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Expanded(
child: Text("Header"),
),
],
),
const SizedBox(height: 20),
const Text("Body: Lorem ipsum dolor sit amet"),
const SizedBox(height: 20),
const Text("Footer"),
],
),
),
),
),
)),
],
),
);
}
BoxShadow _composeShadow({
required double dy,
required double blur,
double spread = 0,
}) {
return BoxShadow(
color: const Color(0xFFDBDBDB),
offset: Offset(0, dy),
spreadRadius: spread,
blurRadius: blur,
);
}
}
Edit:
I have an alternative solution if you can't use the fixed itemExtend, you could use Stack instead of Column:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(kPaddingPage),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(
left: kPaddingItemH,
right: kPaddingItemH,
),
child: _composeCard(MediaQuery.of(context).size.width),
);
}),
),
),
);
}
Widget _composeCard(double maxWidth) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
_composeShadow(dy: 2, blur: 8),
_composeShadow(dy: 0, blur: 1),
],
),
child: Material(
clipBehavior: Clip.antiAlias,
child: InkWell(
child: Container(
padding:
const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text("Header"),
//other elements
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Text(""),
SizedBox(height: 20),
Text("Body: Lorem ipsum dolor sit amet"),
SizedBox(height: 20),
Text("Footer"),
],
),
],
),
),
),
),
)),
],
),
);
}
BoxShadow _composeShadow({
required double dy,
required double blur,
double spread = 0,
}) {
return BoxShadow(
color: const Color(0xFFDBDBDB),
offset: Offset(0, dy),
spreadRadius: spread,
blurRadius: blur,
);
}
}
Related
I want to create the Netflix home page in flutter, and I'm stuck while creating this hover state.
I have created two base widgets. One for the number plus the thumbnail and the other one for the expanded view when the widget is hovered. Then I put them in a stack with an Inkwell where the onHover changes the state to show the expanded widget.
When I hover on the widget, it does switch between the normal state an expanded state, the problem comes when I try to put a list of these widgets together.
When using row (or ListView) to put them together, after hovering, the expanded widget makes the other widgets move. (which is not the wanted behaviour, I want them to overlap)
When I use it with stack, the widgets do overlap but now it isn't scrollable anymore.
I have added the link to the repo for anyone that wants to clone it and try running it themselves, I'm running it on flutter web.
https://github.com/Advait1306/netflix-flutter
Widget with thumbnail and number:
class TopListItem extends StatelessWidget {
final int index;
const TopListItem({Key? key, required this.index}) : super(key: key);
#override
Widget build(BuildContext context) {
const double height = 250;
return SizedBox(
height: height,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset("assets/numbers/$index.svg",
fit: BoxFit.fitHeight, height: height),
Transform.translate(
offset: const Offset(-30, 0),
child: Image.asset("assets/thumbnails/thumb1.jpg"))
],
),
);
}
}
Expanded view widget:
import 'package:flutter/material.dart';
class HoverMovieTrailer extends StatelessWidget {
const HoverMovieTrailer({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
const textTheme = TextStyle(color: Colors.white);
return SizedBox(
width: 400,
height: 400,
child: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: const Color(0xFF242424)),
child: Column(
children: [
Image.asset("assets/backgrounds/background1.jpg"),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: const [
RoundIconButton(icon: Icons.play_arrow_outlined),
SizedBox(width: 5),
RoundIconButton(icon: Icons.add_outlined),
SizedBox(width: 5),
RoundIconButton(icon: Icons.thumb_up_alt_outlined),
SizedBox(width: 5),
],
),
Row(
children: const [
RoundIconButton(icon: Icons.keyboard_arrow_down_outlined),
],
),
],
),
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
"98% Match",
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold
),
),
const SizedBox(width: 5),
Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 1)
),
child: const Text(
"18+",
style: textTheme,
),
),
const SizedBox(width: 5),
const Text(
"4 Seasons",
style: textTheme,
),
const SizedBox(width: 5),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 1)
),
child: const Text(
"HD",
style: textTheme,
),
)
],
),
),
const SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.all(18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
"Captivating",
style: textTheme,
),
const SizedBox(width: 5),
Container(
width: 5,
height: 5,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white54
),
),
const SizedBox(width: 5),
const Text(
"Exciting",
style: textTheme,
),
const SizedBox(width: 5),
Container(
width: 5,
height: 5,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white54
),
),
const SizedBox(width: 5),
const Text(
"Docuseries",
style: textTheme,
),
],
),
),
],
),
),
);
}
}
class RoundIconButton extends StatelessWidget {
final IconData icon;
const RoundIconButton({Key? key, required this.icon}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.transparent,
border: Border.all(width: 2, color: Colors.white)),
margin: const EdgeInsets.all(1),
child: IconButton(
onPressed: () {},
icon: Icon(icon),
color: Colors.white,
),
);
}
}
Combining the widgets in the single widget:
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:netflix_flutter/widgets/hover_movie_trailer.dart';
import 'package:netflix_flutter/widgets/top_list_item.dart';
class TopListItemWithHover extends StatefulWidget {
const TopListItemWithHover({Key? key}) : super(key: key);
#override
State<TopListItemWithHover> createState() => _TopListItemWithHoverState();
}
class _TopListItemWithHoverState extends State<TopListItemWithHover> {
bool hover = false;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: (){},
onHover: (value){
log("Hover value: $value");
setState(() {
hover = value;
});
},
child: Stack(
clipBehavior: Clip.none,
children: [
TopListItem(index: 1),
if(hover) HoverMovieTrailer(),
],
),
);
}
}
Lists:
import 'package:flutter/material.dart';
import 'package:netflix_flutter/widgets/hover_movie_trailer.dart';
import 'package:netflix_flutter/widgets/top_list_item.dart';
import 'package:netflix_flutter/widgets/top_list_item_with_hover.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
height: 400,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
itemCount: 8,
itemBuilder: (context, index) {
return TopListItemWithHover();
},
),
),
),
const SizedBox(height: 50),
SingleChildScrollView(
child: SizedBox(
height: 400,
child: Stack(
fit: StackFit.passthrough,
children: [
for (var i = 10; i >= 0; i--)
Positioned(
left: (i) * 300,
child: TopListItemWithHover(),
)
],
),
),
)
],
),
);
}
}
So finally found the solution to this problem, the way to move forward is to use a stack in SingleChildScrollView.
A mistake that I made is, I did not set the SingleChildScrollView's direction to horizontal. So I added that.
And then one more addition that's needed is -- A empty sized box which has the width of sum of all the items in the stack.
Stack(
clipBehavior: Clip.none,
children: [
const SizedBox(
width: 300*10,
),
for (var i = 10; i >= 0; i--)
Positioned(
left: (i) * 300,
child: TopListItemWithHover(),
)
],
)
This finally expanded the stack to the required width and then made is scrollable also.
My app currently looks like this:
And the here's the code behind it:
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const 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(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.lightBlue),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: [
Card(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24))),
elevation: 30,
child: Padding(
padding: EdgeInsets.only(top: 120, right: 15, bottom: 20, left: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextField(
controller: TextEditingController(text: '12121+1212'),
keyboardType: TextInputType.none,
textAlign: TextAlign.end,
style: TextStyle().copyWith(fontSize: 70),
decoration: InputDecoration(border: InputBorder.none),
),
Align(
alignment: Alignment.centerRight,
child: Text(
'Result',
style: TextStyle().copyWith(fontSize: 36),
),
),
Container(
height: 6,
width: 25,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.all(Radius.circular(14))),
)
],
)),
),
Expanded(child: Container())
]))));
}
}
Now, I want to scroll down the this card to reveal a list above it,something like this:
https://youtu.be/qZtGjd_-KwI
I think it could be done with CustomScrollView, but as a novices CustomScrollView and Slivers are a bit complex for me to understand. A little help regrading how to go about this would be appreciated.
I think you want a CustomScrollView. This will get you close (but won't collapse the main body as in your video example). Note if you provide a hasScrollBody to true then you're body will shrink in response but it'll then overflow. Even a ConstrainedBox with minimum height didn't work for me so that shrinking part is really the hardest part.
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
final centerKey = GlobalKey();
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
center: centerKey,
slivers: [
const SliverAppBar(title: Text('The real title')),
SliverList(
delegate: SliverChildListDelegate.fixed(
[
Container(
color: Colors.pink,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
height: 200.0,
color: Colors.pink,
),
Container(
width: double.infinity,
height: 200.0,
color: Colors.blue,
),
Container(
width: double.infinity,
height: 200.0,
color: Colors.red,
),
],
),
),
],
),
),
SliverAppBar(
key: centerKey,
expandedHeight: 100.0,
backgroundColor: Colors.transparent,
flexibleSpace: const Card(
margin: EdgeInsets.zero,
elevation: 14.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(32.0),
),
),
child: SizedBox.expand(),
),
),
SliverFillRemaining(
hasScrollBody: false,
child: SafeArea(
top: false,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: List.generate(5, (i) => i).map((i) {
return Expanded(
child: Row(
children: List.generate(4, (i) => i).map((i) {
return const Expanded(
child: Placeholder(),
);
}).toList(),
),
);
}).toList(),
),
),
),
),
],
),
);
}
}
The main part you should concern yourself with is the centerKey. That tells the CustomScrollView where it should start from. You pass that to both the CustomScrollView and the SliverAppBar.
The SliverFillRemaining will fill what's left of the viewport, which if you're starting at the SliverAppBar will be about 80%. FillRemaining will take you into the box model (as opposed to the Sliver model) which allows you to just use the space as you regularly would with columns and what not.
I am using the current code at the moment:
class Listing extends StatelessWidget {
#override
Widget build(BuildContext context) {
if (kDebugMode) print ('Building Listing');
return Scaffold(
backgroundColor: Colors.blueGrey[900],
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
for (Booking booking in Provider.of<CP>(context).bookings.values)
ListTileTheme(
// key: Key(booking.orderUID),
contentPadding: EdgeInsets.zero,
// minVerticalPadding: -1.0,
dense: true,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 20.0, vertical: 5.0),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 3), // changes position of shadow
),
],
),
child: StickyHeader(
header: Container(
height: 50.0,
color: Colors.black,
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(DateFormat('E d MMM').format(DateTime.fromMillisecondsSinceEpoch(booking.dateUnix)),
style: headerStyle,
),
),
content: BookingTileView(booking: booking))),
)
],
),
),
),
);
}
}
Currently every item has its own header. It would be nice to have one header for similar items, but I am not sure how to do that? Any help with example code will be much appreciated... Thanks
try to use flutter_sticky_header instead:
import 'package:flutter/material.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
import '../common.dart';
class ListExample extends StatelessWidget {
const ListExample({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppScaffold(
title: 'List Example',
slivers: [//<-----Group of Headers
_StickyHeaderList(index: 0),
_StickyHeaderList(index: 1),
_StickyHeaderList(index: 2),
_StickyHeaderList(index: 3),
],
);
}
}
class _StickyHeaderList extends StatelessWidget {
const _StickyHeaderList({
Key? key,
this.index,
}) : super(key: key);
final int? index;
#override
Widget build(BuildContext context) {
return SliverStickyHeader(//<-----Header
header: Header(index: index),
sliver: SliverList(//<-----Group items
delegate: SliverChildBuilderDelegate(
(context, i) => ListTile(
leading: CircleAvatar(
child: Text('$index'),
),
title: Text('List tile #$i'),
),
childCount: 6,
),
),
);
}
}
I want to use onTap() with GridView and searched in google.
But I did not apply this code.
Therefore could you suggest any solutions?
Recently I started use Flutter and programming.
I think that my question is abstract, so If you have any questions regarding this.
Please feel free to ask me.
Thanks
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,
style: TextStyle(fontFamily: 'OpenSans'),
),
centerTitle: true,
),
body: Container(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget> [
GridView.count(
primary: true,
padding: const EdgeInsets.all(20),
crossAxisSpacing: 10,
mainAxisSpacing: 10,
crossAxisCount: 2,
shrinkWrap: true,
children: <Widget>[
Container(
padding: const EdgeInsets.all(8),
child: const Text("He'd have you all unravel at the"),
color: Colors.teal[100],
),
Container(
padding: const EdgeInsets.all(8),
child: const Text('Heed not the rabble'),
color: Colors.teal[200],
),
Container(
padding: const EdgeInsets.all(8),
child: const Text('Sound of screams but the'),
color: Colors.teal[300],
),
],
),
],
),
)
),
);
}
}
you can use inkwell to make anything clickable
InkWell(
onTap: () {
print('1 was clicked');
},
child: Container(
padding: const EdgeInsets.all(8),
child: const Text('Sound of screams but the'),
color: Colors.teal[300],
),
here is all of you need
import 'package:flutter/material.dart';
import 'package:testflow/clickaletexsheet.dart';
import 'package:testflow/paint.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(
title: Text(
widget.title,
style: TextStyle(fontFamily: 'OpenSans'),
),
centerTitle: true,
),
body: Container(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
GridView.count(
primary: true,
padding: const EdgeInsets.all(20),
crossAxisSpacing: 10,
mainAxisSpacing: 10,
crossAxisCount: 2,
shrinkWrap: true,
children: <Widget>[
Material(
color: Colors.teal[100],
child: InkWell(
onTap: () {
print('1 was clicked');
},
child: Container(
padding: const EdgeInsets.all(8),
child: const Text("He'd have you all unravel at the"),
),
),
),
Material(
color: Colors.teal[200],
child: InkWell(
onTap: () {
print('2 was clicked');
},
child: Container(
padding: const EdgeInsets.all(8),
child: const Text('Heed not the rabble'),
),
),
),
Material(
color: Colors.teal[300],
child: InkWell(
onTap: () {
print('3 was clicked');
},
child: Container(
padding: const EdgeInsets.all(8),
child: const Text('Sound of screams but the'),
),
),
),
],
),
],
),
)),
);
}
}
i also defined the inkwell as child of a material widget and passed the colorof container to material instead of container itself because in that way when you click on one of those, the splash will work if you don't do that user won't find out when clicked on it
read more about inkwell hereinkwell
When press the Add button, it will add a TextField. When I click the minus button, I want the TextField get removed. But it keeps deleting the wrong TextField.
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
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> {
var commentList = List();
TextEditingController _commentsController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample"),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Text("Comments", style: TextStyle(color: Colors.grey)),
SizedBox(width: 20),
Container(
height: 35,
padding: const EdgeInsets.all(10.0),
child: InkWell(
onTap: () {
setState(() {
commentList.insert(
0, _commentsController.text);
});
},
child: Row(children: [
Icon(
Icons.add,
color: Colors.white,
size: 15,
),
SizedBox(width: 5),
Text(
"Add",
style: TextStyle(color: Colors.white),
)
])),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: const Color(0xff0000ff),
)),
]),
SizedBox(height: 15),
Padding(
padding: EdgeInsets.all(10),
child: _showListViewComments()),
],
))));
}
Widget _showListViewComments() {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: commentList.length + 1,
itemBuilder: (BuildContext ctxt, int index) {
if (index < commentList.length) {
return Padding(
padding: EdgeInsets.only(bottom: 10),
child: Row(children: [
Expanded(
child: TextField(
maxLines: 3,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(5.0))),
contentPadding: EdgeInsets.all(10),
))),
SizedBox(width: 10),
Container(
width: 30,
height: 30,
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
setState(() {
print(index);
commentList.removeAt(index);
});
},
child: Icon(
Icons.remove,
color: Colors.white,
),
))
]));
}
});
}
}
Eg: I have text 1 and text 2. I want delete text 1 instead of text 2.
Every TextField should pair with defined TextEditingController. I edited your code to
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,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
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> {
List<TextEditingController> commentList = List();
//TextEditingController _commentsController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample"),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Text("Comments", style: TextStyle(color: Colors.grey)),
SizedBox(width: 20),
Container(
height: 35,
padding: const EdgeInsets.all(10.0),
child: InkWell(
onTap: () {
setState(() {
commentList.add(TextEditingController());
// commentList.insert(
// 0, _commentsController.text);
});
},
child: Row(children: [
Icon(
Icons.add,
color: Colors.white,
size: 15,
),
SizedBox(width: 5),
Text(
"Add",
style: TextStyle(color: Colors.white),
)
])),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: const Color(0xff0000ff),
)),
]),
SizedBox(height: 15),
Padding(
padding: EdgeInsets.all(10),
child: _showListViewComments()),
],
))));
}
Widget _showListViewComments() {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: commentList.length + 1,
itemBuilder: (BuildContext ctxt, int index) {
if (index < commentList.length) {
return Padding(
padding: EdgeInsets.only(bottom: 10),
child: Row(children: [
Expanded(
child: TextField(
maxLines: 3,
controller: commentList[index],
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(5.0))),
contentPadding: EdgeInsets.all(10),
))),
SizedBox(width: 10),
Container(
width: 30,
height: 30,
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
setState(() {
print(index);
commentList.removeAt(index);
});
},
child: Icon(
Icons.remove,
color: Colors.white,
),
))
]));
}
});
}
}