Ignore onTap action on Transparent part of the svg image flutter - flutter

Issue is that their are multiple svg images in stack. I need them to trigger only when the user tapped on filled part of the svg. So that, when it ignores on transparent part of the image, it can able to trigger behind svg image.
Stack(
children: [
GestureDetector(
onTap: () => updateSelectedPart(1),
child: SvgPicture.asset(
'assets/images/1.svg',
color: selectedPart == 1
? Colors.red
: Colors.blue,
),
),
GestureDetector(
onTap: () => updateSelectedPart(2),
behavior: HitTestBehavior.translucent,
child: SvgPicture.asset(
'assets/images/2.svg',
color: selectedPart == 2
? Colors.red
: Colors.blue,
),
),
GestureDetector(
onTap: () => updateSelectedPart(3),
behavior: HitTestBehavior.deferToChild,
child: AbsorbPointer(
absorbing: true,
child: SvgPicture.asset(
'assets/images/3.svg',
excludeFromSemantics: true,
clipBehavior: Clip.none,
color: selectedPart == 3
? Colors.red
: Colors.blue,
),
),
),
],
)

Ordering is bottom to top so you will need to adjust (change order in the stack) so that what might overlay another SVGs transparent part gets triggered on an action (click/touch event) not the SVG below it (Above it in this case as its bottom to top)

Related

How can I apply to image both ink well ripple effect during pressing and shimmer effect during loading?

I would like an image with shimmer effect applied while loading, similar to the fancy_shimmer_image package, to also receive ripple effect from an InkWell. Is there a way to do this?
The only way i found to do that is this "trick". Use a Stack for set a widget on top of your image. And then the inkwell effect works:
Stack(
children: [
// image with shimmer effect
FancyShimmerImage(
imageUrl:
'https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_960_720.jpg',
shimmerBaseColor: Colors.amberAccent,
shimmerHighlightColor: Colors.redAccent,
shimmerBackColor: Colors.greenAccent,
),
//use this widget on top to do the effect
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
// splashColor: Colors.lightGreenAccent,
onTap: () {
print("on tap");
},
),
),
),
],
),
use the shimmer package and cached network image
and use it like that
CachedNetworkImage(
imageUrl: prov
.cart
.cartItems[index]
.image,
placeholder:
(context, url) =>
Shimmer.fromColors(
baseColor: Colors.grey.shade300,
highlightColor: Colors.white,
enabled: true, child: Image.asset(
'assets/images/product_placeholder.png',
),
)
),

onHover effect doesn't work on TextButton nor InkWell

I am developing a Flutter website. I have some links that I want to behave as a normal link: with a different color when the user hovers over them. However, I can't manage to make the color change.
I have tried using a TextButton with the onHover property. I have also tried with an Inkwell onHover property and hoverColor. I have wrapped the InkWell with Material and my onTap function is defined. I have also tried by wrapping this on an AnimatedContainer, but nothing seems to work.
Here is my code.
TextStyle? bodyTextStyle = Theme.of(context).textTheme.bodySmall;
InkWell(
color: Colors.transparent,
child: Text(
"data policy",
style: bodyTextStyle,
),
onTap: () => Navigator.of(context).pushNamed(
Navigation(context).routes["data policy"]),
onHover: (isHovering) {
setState(() {
bodyTextStyle = isHovering
? bodyTextStyle?.copyWith(
color: Theme.of(context).colorScheme.outline)
: bodyTextStyle;
});
},
),
I prefer using InkWell rather than TextButton in order to get rid of the shadow around the text that TextButton creates.
You can follow this snippet, hoverColor from InkWell can overlap.
InkWell(
child: SizedBox(
width: 100,
height: 100,
child: Text(
"Text",
style: linkTextStyle,
)),
onTap: () {},
hoverColor: Colors.transparent, //button splash color
onHover: (isHovering) {
linkTextStyle = isHovering
? TextStyle(color: Colors.red)
: TextStyle(color: Colors.cyanAccent);
setState(() {});
},
),
Also You can check MouseRegion, elevation on buttonStyle.

Flutter GestureDetector onTap in certain page not working

Hi I managed to create a button that will show a tooltip and that tooltip will have a text content and a button, that button will redirect my app to my privacy policy page, the problem is when I redirect my app to that page using the button inside my tooltip.
All of my GestureDetector become disabled / not working even when I tried to do some simple task such as print().
Anyone know how to fix this ?
Here's my code:
ReusableTooltip(
tooltipHeader: '',
tooltipText: 'deviceContactClause',
tooltipDirection: AxisDirection.down,
tooltipChild: Container(
alignment: Alignment.center,
width: 45,
height: 40,
color: Colors.transparent,
child: SvgPicture.asset(
'assets/logo/Information.svg',
),
),
additionalWidget: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const PrivacyPolicyPage()
),
);
},
child: Container(
child: Text('seePrivacyPolicy',
),
),
),
Try this Gesture behavior
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
},
),

How to add a double tap gesture to video player without loosing the focus of controls?

I tried it by wrapping the
return ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Chewie(
controller: _chewieController,
)
with
return Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Chewie(
controller: _chewieController,
),
),
Positioned.fill(child: GestureDetector(
onDoubleTap: (){
print('its double tapped ');
},
child: Container(
color: Colors.transparent,
height: double.infinity,
width: double.infinity,
),))
],
);
Now I am able to doubleTap, but with a single tap, controllers don't appear, Is there any way I can achieve both things.
With a doubleTap, I can call the like function and with onTap to show the controllers.
the package used above chewie 0.12.0
I don't know how Chewie is built but if there is GestureDetector you could change it to something like this:
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => // show_controls,),
onDoubleTap:() => setState(() => // like behaviour,),
child: VideoWidget // or whatever is there
}
So you can have both listeners on one widget. I think that way onTap will be with some slight delay to check if it is not onDoubleTap. That way you don't have to put overlay on top of your widget.
If for some reason you want to have this overlay... then the interesting attribute here is behaviour as it decides if elements behind will receive events.
https://api.flutter.dev/flutter/rendering/PlatformViewHitTestBehavior-class.html
Update
Try changing into
GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTap: (){
print('its double tapped ');
}
OR
In the github project, this line:
https://github.com/flutter/plugins/blob/master/packages/video_player/video_player/example/lib/main.dart#L290
It seems that the controls only show when video is in pause state. Its about this value controller.value.isPlaying.
Why not to control it in your own GestureDetector ?
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _controller.pause() ,), //changing here
onDoubleTap:() => setState(() => // like behaviour,),
child: VideoWidget // or whatever is there
}
Anyway, hope it you will find answer
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (_) {
setState(() {
isMute = !isMute;
_chewieController.setVolume(isMute ? 0 : 1);
});
},
onDoubleTap: (){
print('liked');
},
child: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: Chewie(
controller: _chewieController,
),
),
);
on simple onTap on video, it shows the controller, onTap here is not getting override hence
onTapDown is used as an alternative to onTap to mute the video.

How do I remove Flutter IconButton big padding?

I want to have a row of IconButtons, all next to each other, but there seems to be pretty big padding between the actual icon, and the IconButton limits. I've already set the padding on the button to 0.
This is my component, pretty straightforward:
class ActionButtons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.lightBlue,
margin: const EdgeInsets.all(0.0),
padding: const EdgeInsets.all(0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
IconButton(
icon: new Icon(ScanrIcons.reg),
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
onPressed: () {},
),
IconButton(
icon: new Icon(Icons.volume_up),
alignment: Alignment.center,
padding: new EdgeInsets.all(0.0),
onPressed: () {},
)
],
),
);
}
}
I want to get rid of most of the light blue space, have my icons start earlier on the left, and closer to each other, but I can't find the way to resize the IconButton itself.
I'm almost sure this space is taken by the button itself, 'cause if I change their alignments to centerRight and centerLeft they look like this:
Making the actual icons smaller doesn't help either, the button is still big:
thanks for the help
Simply pass an empty BoxConstrains to the constraints property and a padding of zero.
IconButton(
padding: EdgeInsets.zero,
constraints: BoxConstraints(),
)
You have to pass the empty constrains because, by default, the IconButton widget assumes a minimum size of 48px.
Two ways to workaround this issue.
Still Use IconButton
Wrap the IconButton inside a Container which has a width.
For example:
Container(
padding: const EdgeInsets.all(0.0),
width: 30.0, // you can adjust the width as you need
child: IconButton(
),
),
Use GestureDetector instead of IconButton
You can also use GestureDetector instead of IconButton, recommended by Shyju Madathil.
GestureDetector( onTap: () {}, child: Icon(Icons.volume_up) )
It's not so much that there's a padding there. IconButton is a Material Design widget which follows the spec that tappable objects need to be at least 48px on each side. You can click into the IconButton implementation from any IDEs.
You can also semi-trivially take the icon_button.dart source-code and make your own IconButton that doesn't follow the Material Design specs since the whole file is just composing other widgets and is just 200 lines that are mostly comments.
Wrapping the IconButton in a container simply wont work, instead use ClipRRect and add a material Widget with an Inkwell, just make sure to give the ClipRRect widget enough border Radius 😉.
ClipRRect(
borderRadius: BorderRadius.circular(50),
child : Material(
child : InkWell(
child : Padding(
padding : const EdgeInsets.all(5),
child : Icon(
Icons.favorite_border,
),
),
onTap : () {},
),
),
)
Instead of removing a padding around an IconButton you could simply use an Icon and wrap it with a GestureDetector or InkWell as
GestureDetector(
ontap:(){}
child:Icon(...)
);
Incase you want the ripple/Ink splash effect as the IconButton provides on click wrap it with an InkWell
InkWell(
splashColor: Colors.red,
child:Icon(...)
ontap:(){}
)
though the Ink thrown on the Icon in second approach wont be so accurate as for the IconButton, you may need to do some custom implementation for that.
Here's a solution to get rid of any extra padding, using InkWell in place of IconButton:
Widget backButtonContainer = InkWell(
child: Container(
child: const Icon(
Icons.arrow_upward,
color: Colors.white,
size: 35.0,
),
),
onTap: () {
Navigator.of(_context).pop();
});
I was facing a similar issue trying to render an Icon at the location the user touches the screen. Unfortunately, the Icon class wraps your chosen icon in a SizedBox.
Reading a little of the Icon class source it turns out that each Icon can be treated as text:
Widget iconWidget = RichText(
overflow: TextOverflow.visible,
textDirection: textDirection,
text: TextSpan(
text: String.fromCharCode(icon.codePoint),
style: TextStyle(
inherit: false,
color: iconColor,
fontSize: iconSize,
fontFamily: icon.fontFamily,
package: icon.fontPackage,
),
),
);
So, for instance, if I want to render Icons.details to indicate where my user just pointed, without any margin, I can do something like this:
Widget _pointer = Text(
String.fromCharCode(Icons.details.codePoint),
style: TextStyle(
fontFamily: Icons.details.fontFamily,
package: Icons.details.fontPackage,
fontSize: 24.0,
color: Colors.black
),
);
Dart/Flutter source code is remarkably approachable, I highly recommend digging in a little!
A better solution is to use Transform.scale like this:
Transform.scale(
scale: 0.5, // set your value here
child: IconButton(icon: Icon(Icons.smartphone), onPressed: () {}),
)
You can use ListTile it gives you a default space between text and Icons that would fit your needs
ListTile(
leading: Icon(Icons.add), //Here Is The Icon You Want To Use
title: Text('GFG title',textScaleFactor: 1.5,), //Here Is The Text Also
trailing: Icon(Icons.done),
),
I like the following way:
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () {},
child: Container(
padding: const EdgeInsets.all(8),
child: const Icon(Icons.favorite, color: Colors.red),
),
),
enter image description here
To show splash effect (ripple), use InkResponse:
InkResponse(
Icon(Icons.volume_up),
onTap: ...,
)
If needed, change icons size or add padding:
InkResponse(
child: Padding(
padding: ...,
child: Icon(Icons.volume_up, size: ...),
),
onTap: ...,
)