Even if the ModalBarrier is wrapped with a GestureDetector, it doesn't trigger taps outside the Container. But replace ModalBarrier with Container and it works.
The Container becomes a workaround but why doesn't it work with ModalBarrier?
Here's the code:
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: _onDropdownTap(),
child: Stack(
fit: StackFit.expand,
children: [
ModalBarrier(
color: Colors.black26,
),
Positioned(
left: width/2 - cardWidth/2,
top: height/2 - cardHeight/2,
width: dropdownWidth,
height: dropdownHeight,
child: Container(
color: Colors.red,
),
),
],
),
);
Related
I need to increase the tap area for gesture detector. I tried wrapping it in a stack and added gesture detector to the top widget which is basically an empty container
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
_button(),
GestureDetector(
behavior: HitTestBehavior.translucent,
child: Container(
height: 80,
width: 80,
color: Colors.redAccent.withOpacity(0.5), // remove this
),
onTap: () {
print('tapped');
},
onPanUpdate: (details) => ....,
onPanEnd: (details) => ....,
)
],
);
}
Screenshot
As you can see in the screenshot I have a text which can be scaled in height. In order to do so I have added a button:
Widget _button() {
return Material(
color: Colors.grey[500],
child: Container(
alignment: Alignment.center,
child: SizedBox(
height: widget.size / 4,
width: widget.size,
),
),
);
}
But I need to increase the tap area and so the stack solution. But it's not working unless I tap in the center(right on top of the _button()). Why is that happening even when I wrapped the empty container with gesture detector?
The top button in the screenshot attached is positioned on the dash lines:
return Stack(
clipBehavior: Clip.none,
fit: StackFit.passthrough,
children: <Widget>[
child,
Positioned(
top: -25,
right: widget.item!.width / 2,
child: TopScaleButton(
widget.item!,
size: buttonSize,
canvasKey: canvasKey,
),
),
],
);
}
AFAIK, in a stack, the widget are stacked on to of each other, so you might need to switch the order of your two widgets in the stack.
StreamBuilder
Listview.builder
Card(
child: Container(
width: double.infinity,
padding: EdgeInsets.all(10),
child: Column(
children: [
CardMenuTitle(id: menu.title),
CardMenuImage(menu: menu, index: index),
... ]
...
Now in cardmenuimage
Widget build(BuildContext context) {
return Stack(
children: [
Container(), //just tried to add empty container to see if it fixes the problem
Positioned(
top: 1, //if I remove this line, it works,
child: Container(
width: double.infinity,
// needed
color: Colors.transparent,
child: Image.asset(
"assets/images/menu/${menu.image}",
fit: BoxFit.cover,
),
),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
splashColor: Colors.black.withOpacity(0.5),
onTap: () {
}, // needed
),
),
),
],
);
}
}
The following assertion was thrown during performLayout():
BoxConstraints forces an infinite width.
These invalid constraints were provided to _RenderColoredBox's layout() function
by the following
function, which probably computed the invalid constraints in question:
RenderConstrainedBox.performLayout
(package:flutter/src/rendering/proxy_box.dart:279:14)
The offending constraints were:
BoxConstraints(w=Infinity, 0.0<=h<=Infinity)
Positioned(
top: 1, //if I remove this line, it works,
child: Container( //removing container solves the problem but image is not displayed
width: double.infinity,
// needed
color: Colors.transparent,
child: Image.asset(
"assets/images/menu/${menu.image}",
fit: BoxFit.cover,
),
),
),
After removing the container from the position widget, the error goes away but image is not displayed.
replace width: double.infinity with width: MediaQuery.of(context).size.width
I'm trying to implement a "Change my profile picture" icon like how it appears in the profile page in Whatsapp, where a clickable camera icon hovers on the bottom right of the image.
This is the code I used inside a stateful widget:
Row(
children: <Widget>[
Stack(
children: <Widget>[
Container(
width: 120,
child: Image(
image: AssetImage('affogato.png'),
),
),
Positioned(
top: 70,
left: 90,
child: FloatingActionButton(
child: Icon(Icons.camera_alt),
onPressed: () {},
),
),
],
),
],
),
Strangely, the Icon seems to take the constraints of the Image container. So when I set the width as 120 and try to push the Icon button to the bottom right edge of the Image, it gets cut off by the Image constraints. How do the constraints of the Container affect the FloatingActionButton even though they're siblings inside the Stack not parent-child widgets? And how can I fix this so that the Icon can float over the edge of the image?
You can probably make use of height property of Positioned widget and adjust other dimensions (left, bottom, right, top) so that the button isn't cut-off at bottom right edge and is displayed properly. Working sample code below:
return Scaffold(
body: Center(
child: Row(
children: <Widget>[
Stack(
children: <Widget>[
Container(
width: 120,
child: Image(
image: AssetImage('assets/Icon-512.png'),
),
),
Positioned(
bottom: 0,
right: 0,
left: 78,
height: 35,
child: FloatingActionButton(
child: Icon(Icons.camera_alt),
onPressed: () {},
),
),
],
),
],
),
)
// This trailing comma makes auto-formatting nicer for build methods.
);
You might need to adjust dimensions per your need, but this way it doesn't cut-off the button.
Hope this answers your question.
Here's how I did it. I removed the Positioned widget completely and used Padding instead. It seemed to solve the problem. I also wrapped the image in a CircleAvatar to complete the Whatsapp style.
Row(
children: <Widget>[
Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: CircleAvatar(
radius: 70,
backgroundColor: Colors.greenAccent,
child: Container(
height: 150,
width: 150,
child: ClipOval(
child: Image(
image: AssetImage('lib/rainy.png'),
),
),
),
),
),
Padding(
padding: EdgeInsets.only(left: 105, top: 80),
child: Container(
width: 50,
height: 50,
child: FloatingActionButton(
backgroundColor: Colors.green,
child: Icon(Icons.camera_alt),
onPressed: () async {},
),
),
),
],
),
],
),
I have a Draggable container, and another container that is supposed to get position of draggable content.
return SizedBox.expand(
child: Column(
children: <Widget>[
Draggable(
child: Container(
width: 50,
height: 56,
color: Colors.orange,
),
feedback: Container(
width: 50,
height: 56,
color: Colors.orange,
),
),
SizedBox.fromSize(
size: Size(500, 500),
child: Listener(
onPointerSignal: (PointerSignalEvent details) => print('get updates here'),
child: Container(
color: Colors.pink.withOpacity(0.2),
),
),
),
],
),
);
How to receive any movement on top of a container? onPanUpdate works only for pan originated in that container.
The same goes for onPointerMove from Listener.
Suppose you have a few nested InkResponse, if you tap on the inner one, all of the parent will actually trigger the splash effect even though they will loose in the tap arena for the right tapped widget. The effect will be something like this:
How to prevent such behavior? How to display the splash only for the tapped widget? In this example image it's being used a Container > Row (with InkReponse) > Icon (also with InkResponse). This will also happen if you use material buttons.
You might want to try IgnorePointer
I encourage you to use Stack widget because you can be able to put together multiple widgets. Here there is an example of a container with inner container and they are both clickable independently,
Stack(
children: [
InkWell(
onTap: (){},
child: Container(
width: 400,
height: 400,
color: Colors.green,
),
),
Positioned(
top: 30,
left: 20,
child: InkWell(
onTap: (){},
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
))
],
)
This worked for me
Center(
child:Container(
width: 100,
height: 100,
child: Card(
child: InkWell(
splashColor: color3,
onTap: () {
},
child: Column(
children: [
SizedBox(
height: 10,
),
IconButton(
splashRadius: 7,
splashColor: Colors.pink,
onPressed: () {},
icon: SvgPicture.asset(
ImageConst.bellIcon,
width: 20,
height: 20,
color: Colors.black,
),
),
SizedBox(
height: 10,
),
Text("text"),
],
),
),
),
),
)
Try to wrap the icon into GestureDetector with the empty handler + Padding.