Flutter onTap method for Containers - user-interface

Been developing a flutter app and dynamicly building some containers from some Firebase data.
I wanted to know if there is a way to get a onTap method for containers (or any widget which is not a button ?
Here is a code sample :
child: new Container(
//INSERT ONTAP OR ONPRESSED METHOD HERE
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 16.0),
child: new GoogleUserCircleAvatar(snapshot.value['images'][0]),
),
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children : [
new Container(
padding: const EdgeInsets.only(bottom: 8.0),
child: new Text("${snapshot.value['name']}",
style: new TextStyle(
fontWeight: FontWeight.bold,
),
),
),
new Text("${snapshot.value['description']}",
style: new TextStyle(
color: Colors.grey[500],
),
),
]
)
],
),

You can wrap your Container in an InkWell or GestureDetector. The difference is that InkWell is a material widget that shows a visual indication that the touch was received, whereas GestureDetector is a more general-purpose widget that shows no visual indicator.

You could wrap container inside an Inkwell() or in GestureDetector() as below
InkWell(
child: Container(...),
onTap: () {
print("tapped on container");
},
);
Using the Gesture Detector
GestureDetector(
onTap: () { print("Container was tapped"); },
child: Container(...),
)
The only difference between the two is InkWell provides a ripple effect when the pointer is in contact with the screen while this is no such visual feedback with GestureDetector.

Screenshot:
You can use both GestureDetector and InkWell but I'll suggest you to go for InkWell as it can show ripple effects which a GestureDetector can't.
Differences between GestureDetector and InkWell:
Both share many features in common like onTap, onLongPress etc. The main difference is that GestureDetector has more controls like dragging and so on. On the other hand, InkWell provides some nice ripple effects.
You can use either of them according to your needs. If you want ripple effect choose InkWell, and if you need more controls then go with GestureDetector or even combine both of them.
Material(
color: Colors.blue, // Background color
child: InkWell(
splashColor: Colors.grey, // Splash color
onTap: () => print("Container pressed"), // Handle your onTap here.
child: Container(height: 200, width: 200),
),
)

Apart from what others have said in answers, if you use Card inside InkWell, then InkWell will hide away the ripply effect on Android—you can see it happening in the background but not on the card itself.
Solution to that is to create an InkWell inside the Card.
return Card(
child: InkWell(
child: Row(
// Row content
),
onTap: () => {
print("Card tapped.");
},
),
elevation: 2,
);
This will help you gain the ripple effect and perform the tap captures on Android too.

Related

Place widget in exact coordinate within image

In my application I have an image that can be zoomed in or out. I want to place another widget over the image and get them both scale at the same time.
The idea is first image has a window in it. I want to place 2nd image with in the window area.
I got the image scaling working with the following code. What I don't know is how to place another widget within exact area within the 1st image.
_buildWindowImage() {
return Transform.scale(
scale: _imageScale,
alignment: Alignment.topCenter,
child: Image.asset(
'assets/images/background/window_1.png',
fit: BoxFit.contain,
),
);
}
Can someone provide some help on this.
you can do
_buildWindowImage() {
return Transform.scale(
scale: _imageScale,
alignment: Alignment.topCenter,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/background/window_1.png',
),
fit: BoxFit.contain,
),
),
child: Center(_put_another_widget_here),
),
);
}
}

How to do spin animation like wheel with onSwipe event in flutter?

I have an image of wheel and trying to add spin animation on it with onSwipe event.
actually what I did..
I used AnimatedBuider class but image is spinning on initially.
Here the image
AnimatedBuilder(
animation: animationController,
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/wheel.png", ),
fit: BoxFit.contain,
),
borderRadius: BorderRadius.all(Radius.circular(210.0)),
),
height: MediaQuery.of(context).size.height/2.3,
width: MediaQuery.of(context).size.width/1,
),
builder: (BuildContext context, Widget _widget) {
return new Transform.rotate(
angle: animationController.value * 6.3,
child: _widget,
);
},
),
Animation controller
#override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 7),
);
animationController.repeat();
}
I found the solution from flutter_spinning_wheel package

Unable to load asset: assets/ in Material children<Widget>

I am asking this question after going through may SO question's.
I have tried a lot of answers. But non of them is working for me !!
Most of the questions in SO are using MaterialApp, but I am returning normal Material class bcoz I don't want Actionbar or anything like that.
What I am trying to achieve?
I am trying to make a simple Login Screen, where App icon is on the top, then Username, Password & Login Button are following the App Icon.
But alas ! App icon is not getting loaded on the AssetImage.
Below is my code
class Login extends StatelessWidget{
#override
Widget build(BuildContext context) {
return new Material(
color: Color.fromARGB(255, 0, 68, 178),
child: new Container(
margin: const EdgeInsets.all(5.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
//This will have Login EditTexts....
children: <Widget>[
//Adding Logo on Login Screen....
//NOT WORKING
// new DecoratedBox(
// decoration: BoxDecoration(
// image: DecorationImage(
// image: AssetImage("assets/app_logo.jpg")
// )
// ),
// ),
//NOT WORKING
// new ImageIcon(
// new AssetImage("assests/app_logo.jpg"),
// size: 24.0,
// color: Colors.white,
// ),
//NOT WORKING
// new Container(
// decoration: new BoxDecoration(
// image: new DecorationImage(
// colorFilter: new ColorFilter.mode(
// Colors.black.withOpacity(0.6),
// BlendMode.dstATop
// ),
// image: new AssetImage("assets/applogo.jpg"),
// fit: BoxFit.contain
// )
// )
// ),
//NOT WORKING
// new Image.asset(
// 'assets/applogo.jpg',
// height: 60.0,
// fit: BoxFit.cover,
// ),
//NOT WORKING
new Directionality(
textDirection:TextDirection.ltr,
child: new Image.asset(
"assets/applogo.jpg",
height: 100.0,
width: 100.0,
fit: BoxFit.contain
)
),
//WORKING
new Text("Lets Login....", textDirection: TextDirection.ltr),
//WORKING
//Username TextField goes below....
new Directionality(
textDirection: TextDirection.ltr,
child: new TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter Username:'
),
)
),
//WORKING
//Password TextField goes below......
new Directionality(
textDirection:TextDirection.ltr,
child: new TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText:"Enter Password:"
)
)
),
//WORKING
//Login Button with Inkwell goes below....
new Directionality(
textDirection:TextDirection.ltr,
child: new InkWell(
child : new RaisedButton(
padding: const EdgeInsets.all(8.0),
textColor: Colors.white,
color: Colors.blue,
onPressed: login,
child: new Text("Login", textAlign: TextAlign.center, textDirection: TextDirection.ltr)
)
)
)
],
),//child Column closes here...
),//Container closes here.....
);//return Material closes here....
}//build closes here.....
void login(){
print("Login Pressed...");
}//login closes here....
}//Login class closes here....
Below is my pubspec.yaml
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/
- assets/app_logo.jpg
There are some typos in your code when you tried referencing the image asset such as "assets/applogo.jpg" or "assests/app_logo.jpg". Try this for example:
Image.asset(
"assets/app_logo.jpg",
height: 60.0,
fit: BoxFit.cover
),

Container height Animation starts from the middle

The Flutter Container height animation starts from the middle, but I need it to start from the bottom here is my code
import 'dart:math';
import 'package:flutter/material.dart';
class CorrectWrongOverlay extends StatefulWidget {
final bool _isCorrect;
final VoidCallback _onTap;
final double percentR;
final double percentW;
CorrectWrongOverlay(
this._isCorrect, this.percentR, this.percentW, this._onTap);
#override
State createState() => CorrectWrongOverlayState();
}
class CorrectWrongOverlayState extends State<CorrectWrongOverlay>
with SingleTickerProviderStateMixin {
Animation<double> _iconAnimation;
AnimationController _iconAnimationController;
#override
void initState() {
super.initState();
_iconAnimationController = AnimationController(
duration: Duration(seconds: 3), vsync: this);
_iconAnimation = CurvedAnimation(
parent: _iconAnimationController, curve: Curves.fastOutSlowIn);
_iconAnimation.addListener(() => this.setState(() {}));
_iconAnimationController.forward();
}
#override
void dispose() {
_iconAnimationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.black54,
child: InkWell(
onTap: () => widget._onTap(),
child: Padding(
padding: const EdgeInsets.all(18.0),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: 80.0,
height: 200.0 * _iconAnimation.value,
color: Colors.green,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: 80.0,
height: 200.0,
color: Colors.green,
),
)
],
),
),
),
),
);
}
}
I am trying to achieve this kind of UI with height grow animations in Flutter I want the animations to start from the bottom but it starts from the center of the container and animated it both side.
to start scale animation from certain points. You can wrap your Container with Align widget and give certain start positions with simplicty.
define your controller and animation variables;
AnimationController animationController;
Animation<double> tween;
init them in initState method;
#override
void initState() {
super.initState();
animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 800));
tween = Tween<double>(begin:0,end:1).animate(CurvedAnimation(parent: animationController, curve: Curves.easeIn));
animationController.addListener(() {
setState(() {});
});
}
then in build method or where ever you add use return Widget like below;
Widget animatedContainer(){
return Align(
alignment: Alignment.topRight,// .topCenter, .topLeft, .bottomLeft, bottomCenter...etc
child: Container(
width: (size.width * tween.value).abs(),
height: (200 *tween.value).abs(),
color:Colors.red
),
);
}
You could use TweenMax for Flutter package: https://pub.dartlang.org/packages/tweenmax
Here is an example: https://github.com/mrgoonie/flutter_tweenmax/blob/master/lib/screens/animated_column_chart.dart
Click on the bottom button to animate those bars.
Cheers,
If you're animating it once and don't require advanced animation control, then you don't even need to keep track of AnimationController yourself. Just use TweenAnimationBuilder, pass to it your tween, duration and curve, and let it animate widget for you:
Widget _animatedBarWidget(Widget barWidget) => TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 1.0),
duration: const Duration(seconds: 3),
curve: Curves.fastOutSlowIn,
builder: (BuildContext context, double value, Widget? child) {
return Align(
alignment: Alignment.bottomCenter,
heightFactor: value,
child: child!,
);
},
child: barWidget,
);
Then, just call
_animatedBarWidget(Container(width: 80.0, height: 200.0, color:Colors.red));

How do I stretch an image to fit the whole background (100% height x 100% width) in Flutter?

I have an image that doesn't match the aspect ratio of my device's screen. I want to stretch the image so that it fully fills the screen, and I don't want to crop any part of the image.
CSS has the concept of percentages, so I could just set height and width to 100%. But it doesn't seem like Flutter has that concept, and it's bad to just hard code the height and width, so I'm stuck.
Here's what I have (I'm using a Stack since I have something in the foreground of the image):
Widget background = new Container(
height: // Not sure what to put here!
width: // Not sure what to put here!
child: new Image.asset(
asset.background,
fit: BoxFit.fill, // I thought this would fill up my Container but it doesn't
),
);
return new Stack(
children: <Widget>[
background,
foreground,
],
);
To make an Image fill its parent, simply wrap it into a FittedBox:
FittedBox(
child: Image.asset('foo.png'),
fit: BoxFit.fill,
)
FittedBox here will stretch the image to fill the space.
(Note that this functionality used to be provided by BoxFit.fill, but the API has meanwhile changed such that BoxFit no longer provides this functionality. FittedBox should work as a drop-in replacement, no changes need to be made to the constructor arguments.)
Alternatively, for complex decorations you can use a Container instead of an Image – and use decoration/foregroundDecoration fields.
To make the Container will its parent, it should either:
have no child
have alignment property not null
Here's an example that combines two images and a Text in a single Container, while taking 100% width/height of its parent:
Container(
foregroundDecoration: const BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://p6.storage.canalblog.com/69/50/922142/85510911_o.png'),
fit: BoxFit.fill),
),
decoration: const BoxDecoration(
image: DecorationImage(
alignment: Alignment(-.2, 0),
image: NetworkImage(
'http://www.naturerights.com/blog/wp-content/uploads/2017/12/Taranaki-NR-post-1170x550.png'),
fit: BoxFit.cover),
),
alignment: Alignment.bottomCenter,
padding: EdgeInsets.only(bottom: 20),
child: Text(
"Hello World",
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.white),
),
),
The following will fit the image to 100% of container width while the height is constant.
For local assets, use AssetImage
Container(
width: MediaQuery.of(context).size.width,
height: 100,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage("https://picsum.photos/250?image=9"),
),
),
)
Image fill modes:
Fill - Image is stretched
fit: BoxFit.fill
Fit Height - image kept proportional while making sure the full height of the image is shown (may overflow)
fit: BoxFit.fitHeight
Fit Width - image kept proportional while making sure the full width of the image is shown (may overflow)
fit: BoxFit.fitWidth
Cover - image kept proportional, ensures maximum coverage of the container (may overflow)
fit: BoxFit.cover
Contain - image kept proportional, minimal as possible, will reduce it's size if needed to display the entire image
fit: BoxFit.contain
Inside your Stack, you should wrap your background widget in a Positioned.fill.
return new Stack(
children: <Widget>[
new Positioned.fill(
child: background,
),
foreground,
],
);
For me, to develop for web, works fine the following:
Image(
image: AssetImage('lib/images/portadaSchamann5.png'),
alignment: Alignment.center,
height: double.infinity,
width: double.infinity,
fit: BoxFit.fill,
),
Might not be exactly what the OP was looking for, but this page is where I found myself after looking for the problem, so sharing this for everyone with similar issue :)
Stack's fit property did the trick for my needs. Otherwise Image inside (OctoImageIn my case) was padded and providing other Image.fit values did not give any effect.
Stack(
fit: StackFit.expand,
children: [
Image(
image: provider,
fit: BoxFit.cover,
),
// other irrelevent children here
]
);
Your Question contains the first step, but you need width and height. you can get the width and height of the screen. Here is a small edit
//gets the screen width and height
double Width = MediaQuery.of(context).size.width;
double Height = MediaQuery.of(context).size.height;
Widget background = new Image.asset(
asset.background,
fit: BoxFit.fill,
width: Width,
height: Height,
);
return new Stack(
children: <Widget>[
background,
foreground,
],
);
You can also use Width and Height to size other objects based on screen size.
ex: width: Height/2, height: Height/2 //using height for both keeps aspect ratio
I think that for your purpose Flex could work better than Container():
new Flex(
direction: Axis.vertical,
children: <Widget>[
Image.asset(asset.background)
],
)
The best example for this question I found on this page:
https://flutterbeads.com/set-background-image-in-flutter/
By using BoxDecoration and DecorationImage:
Container(
constraints: BoxConstraints.expand(),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/cat2.jpg"),
fit: BoxFit.cover),
)
None of the above answers worked for me. And since there is no accepted answer, I found the following extended my image from horizontal edge to horizontal edge:
Container ( width: MediaQuery
.of(context)
.size
.width,
child:
Image.network(my_image_name, fit: BoxFit.fitWidth )
)
Visit https://youtu.be/TQ32vqvMR80
OR
For example if parent contrainer has height: 200, then
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('url'),
fit: BoxFit.cover,
),
),
),
This should work,
Image.asset('assets/bg.jpg',fit: BoxFit.cover,),
I set width and height of a container to double.infinity like so:
Container(
width: double.infinity,
height: double.infinity,
child: //your child
)
This will work if you want to add a fit background image in Flutter:
class Myname extends StatelessWidget {
const Myname({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/aj.jpg"),
fit: BoxFit.cover,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(),
),
),
),
);
}
}
Now you can add the rest of the things inside the Column()
For filling, I sometimes use SizedBox.expand
I ran into problems with just an FittedBox so I wrapped my Image in an LayoutBuilder:
LayoutBuilder(
builder: (_, constraints) => Image(
fit: BoxFit.fill,
width: constraints.maxWidth,
image: AssetImage(assets.example),
),
)
This worked like a charm and I suggest you give it a try.
Of course you can use height instead of width, this is just what I used.
For me, using Image(fit: BoxFit.fill ...) worked when in a bounded container.
This worked for me
class _SplashScreenState extends State<SplashScreen> {
#override
Widget build(BuildContext context) {
return Container(
child: FittedBox(
child: Image.asset("images/my_image.png"),
fit: BoxFit.fill,
),);
}
}
Try setting contentPadding
ListTile(
contentPadding: EdgeInsets.all(0.0),
...
)
I didn’t find answer in this post, But I found the fix:
Positioned(
bottom: 0,
top: 0,
child: Image.asset(
'assets/images/package_bg.png',
)),
This code make image fit to height on the stack.

Resources