Flutter: how can I make a rounded PopupMenuButton's InkWell? - flutter

I have a PopupMenuButton inside a FloatingActionButton. But it's InkWell is not rounded, it is standard square shape. How can I achieve that?

Use customBorder property of InkWell:
InkWell(
customBorder: CircleBorder(),
onTap: () {}
child: ...
)

You can use borderRadius property of InkWell to get a rounded Ink Splash.
Material(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(25.0),
child: InkWell(
splashColor: Colors.blue,
borderRadius: BorderRadius.circular(25.0),
child: Text('Button'),
),
),

To change the InkWell's shape to rounded from standard square shape, Material's borderRadius property is used. Example code is given below -
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green,
child: Material(
color: Colors.yellow,
borderRadius: BorderRadius.all(Radius.circular(5.0)),
child: InkWell(
child: PopupMenuButton(
//shape is used to change the shape of popup card
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
child: Icon(Icons.mode_edit, size: 22.0, color: Colors.red,),
itemBuilder: (context) => [
PopupMenuItem(
child: Text("Child 1"),
),
PopupMenuItem(
child: Text("Child 2"),
),
],
),
),
),
),

I faced a similar issue where the child of the PopupMenuButton would have a square InkWell around it.
In order to make it behave like an IconButton, which naturally uses the rounded InkWell, I simply had to use the icon paramater instead of the child.
icon: Icon(Icons.more_vert),
This is indicated in the documentation for that paramater:
/// If provided, the [icon] is used for this button
/// and the button will behave like an [IconButton].
final Widget icon;

Wrap the Inkwell with Material. Add Border Radius
Material(
borderRadius: BorderRadius.all( // add
Radius.circular(20)
),
child: InkWell(
child: Ink(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text(
"Kayıt Ol",
style: TextStyle(
color: cKutuRengi,
),
),
),
),
)
Here's how to make the tap effect look right
Material(
borderRadius: BorderRadius.all(
Radius.circular(20)
),
child: InkWell(
customBorder:RoundedRectangleBorder( // add
borderRadius: BorderRadius.all(
Radius.circular(20)
)
),
onTap: () {
debugPrint("on tap");
},
child: Ink(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text(
"Kayıt Ol",
style: TextStyle(
color: cKutuRengi,
),
),
),
),
)

Most of the answers here are not using PopupMenuButton like the question specified. If you're simply using an icon child then you can use the icon property rather than child as already explained above, but if you want rounded corners on some other child, you wrap it with a Material, and wrap that with a ClipRRect See this Stackoverflow

Related

Flutter how to make a selectable / focusable widget

I am creating an android tv app. I was trying to work out for a long time why when I clicked the arrow up and down buttons on the remote it appeared to do nothing and it wasn't selecting any of the list item.
Eventually I was able to work out that if I used an elevated button or other focusable widget on the list i could use the arrow keys and it would work fine. Previously I was using a card widget wrapped in a gesture detector.
So I am wondering what the difference between a button and card with gesture detector is that stops the arrow keys from being able to select the item. I suspect it is the focus.
This is what I was using that doesn't allow the up, down keys on the remote to select it:
GestureDetector(
child: Card(
color: color,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: SizedBox(
width: (width / numberOfCards) - padding * (numberOfCards - 1),
height: (height / 2) - padding * 2,
child: Center(child: Text(cardTitle, style: Theme.of(context).textTheme.bodyText1?.copyWith(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),))),
),
onTap: () => onCardTap(),
),
And this is the button I replaced it with that then makes the up down keys and selection to work:
ElevatedButton(
onPressed: () {},
child: Text('Test 1', style: Theme.of(context).textTheme.bodyText1?.copyWith(color: Colors.white, fontSize: 18, fontWeight: FontWeight.normal)),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.grey.withOpacity(0.3)),
minimumSize: MaterialStateProperty.all(Size(60, 60)),
elevation: MaterialStateProperty.all(10),
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: new BorderRadius.circular(50)),)),
),
In case its needed this is what I am using to pick up the key presses:
Shortcuts(
shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
},
Thanks
The difference between your card with gesture detector and the ElevatedButton is that you don't have a FocusNode.
If you dig into the implementation details of the ElevatedButton you will find that it uses an InkWell with a FocusNode
final Widget result = ConstrainedBox(
constraints: effectiveConstraints,
child: Material(
// ...
child: InkWell(
// ...
focusNode: widget.focusNode,
canRequestFocus: widget.enabled,
onFocusChange: updateMaterialState(MaterialState.focused),
autofocus: widget.autofocus,
// ...
child: IconTheme.merge(
// ....
child: Padding(
padding: padding,
child: // ...
),
),
),
),
),
);
So, if you replace GestureDetector with Inkwell, then the keyboard navigation would work.
InkWell(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: const SizedBox(
width: 200,
height: 60,
child: Center(
child: Text(
'Test 1',
),
),
),
),
onTap: () {},
)
(Tested on Android TV emulator API 30, with keyboard an d-pad.)
References
Arrow (also D-PAD) keys don't work for focus traversal of TextFormField #49335 | github.com/flutter
Shift+Tab and arrow (also D-PAD) keys don't work for focus traversal of TextFormField | stackoverflow.com
How to let flutter apps support TV device? | stackoverflow.com

Flutter Material() in ListView builder decoration

How to change Material() border color i have this code, inkWell is a child of sliable widget that also returned in ListView.builder
child:InkWell(
onTap: (){
},
child: Material(
color: Colors.blueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: buildListTile(item),
)
));
i need something like
also i can use only Material() class because my ListView.builder return me Sliable widget from Sliable library, and this is only widget i found that must work fine with desing that i wont
You can change the border of the Material widget using the side property inside your RoundedRectangleBorder.
I also typically put the InkWell inside the Material widget too.
Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
side: const BorderSide(color: Colors.blueAccent),
),
child: InkWell(
borderRadius: BorderRadius.circular(18),
onTap: () {},
child: const ListTile(title: Text('item')),
),
),
),
You can use Card also try below code hope its help to you I have tried same as your image.
Card(
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.green.shade300),
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: [
ListTile(
leading: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('OK'),
Text('OK'),
],
),
title: Text('name'),
),
],
),
),
Your result screen->

How do I remove the empty space at the beginning of a card in Flutter?

So I have this card:
and I want to make it so the blue box looks like this:
how would I do this?
my code is this:
child: Card(
elevation: 5.0,
child: ListTile(
onTap: () {},
title: Text(tasks[index].title),
subtitle: Text(tasks[index].description, overflow: TextOverflow.ellipsis, maxLines: 1,),
leading: ClipRRect(
borderRadius: BorderRadius.circular(2.0),
child: SizedBox(
height: 60.0,
width: 10.0,
child: DecoratedBox(
decoration: BoxDecoration(
color: Colors.blue,
),
),
),
)
),
),
Check the DevTools here https://flutter.dev/docs/development/tools/devtools/overview
They are super useful especially for when there is something wrong with the layout of your widgets, you can see exactly what is wrong woth that widget.
Im guessing its the SizedBox width:10.

Ripple effect not working with when wrapping a Card in InkWell

After doing a bit of research, I tried to wrap ListTiles with InkWell to get the onTap ripple effect, but it doesn't seem to work. This is what I have:
return AnimationLimiter(
child: Scrollbar(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.myItems.length,
itemBuilder: (context, index) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Material(
/// child: Ink( also tried with Ink and no Ink and no Material just InkWell but no ripple
child: InkWell(
onTap: () => widget.nav(widget.myItems[index]),
splashColor: Colors.red,
child: Card(
child: _itemTile(index),
),
),
),
),
),
),
),
),
);
The ListTile:
return ListTile(
dense: true,
trailing: Icon(Icons.keyboard_arrow_right),
leading: category,
title: Text(
item.title,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
);
I managed to get the ripple effect working by doing onTap: () => {} to the InkWell. But after adding the GestureDetector, the Ripple is gone again.
child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () {},
splashColor: Colors.red,
child: GestureDetector(
onTap: () => widget.nav(widget.myItems[index]),
child: _itemTile(index),
),
),
I even tried this, ripple works, but it the widget.nav function doesn't get called:
Stack(
children: [
Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin:
EdgeInsets.only(bottom: 5.0, left: 2.0, right: 2.0),
child: GestureDetector(
onTap: () {
widget.nav(widget.myItems[index]);
},
child: _itemTile(index),
),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => {},
),
),
)
],
),
Edit* Adding the nav function:
_navToItem(item) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Item(
items: _activityItems.length > 0 ? _activityItems : _items,
showAd: false,
user: userStream,
item: item,
favorites: _favorites,
),
),
);
}
ListTile has a ripple effect by default, so you shouldn't need to add an inkwell. If there isn't a ripple, one of the children is probably causing some issues. Try removing some and see if that helps.
Example
You're correct in using the Stack.
It's necessary due to the way the widget tree is rendered from bottom up, layering each widget on top of each other (which blocks the visual effect of splash if there are children below it.)
The GestureDetector you have in your Stack example won't ever get the tap gesture, cause InkWell below it is taking the event.
Something like this work for you? (Move your widget.nav call to the InkWell onTap:.)
Stack(
children: [
Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin:
EdgeInsets.only(bottom: 5.0, left: 2.0, right: 2.0),
// GESTUREDETECTOR Removed ****************
child: Text('itemTile goes here'),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => print('InkWell tapped! Put widget.nav here!'),
),
),
)
],
)
Please try to understand the concept of it. You should provide some margin to the widget to show the effects. You didn't provide any margin or align so it has no space to show the effects.
Below exp. show the effects in all the page because center creates margin from all the side. The Centre aligns its child widget from the top, left, right and bottom.
Widget build(BuildContext context) {
return Center(
child: Material(
child: new InkWell(
onTap: () {
print("tap");
},
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.red,
),
),
),
),
);
}
In your case:
return AnimationLimiter(
child: Scrollbar(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.myItems.length,
itemBuilder: (context, index) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Material(
/// child: Ink( also tried with Ink and no Ink and no Material just InkWell but no ripple
child: InkWell(
onTap: () => widget.nav(widget.myItems[index]),
splashColor: Colors.red,
child: Center(
child: Card(
child: _itemTile(index),
),
),
),
),
),
),
),
),
),
);
For ListTile case try passing custom ripple color. May be your background and your ripple effect color is same.
There is no need to wrap ListTile with InkWell because it already does it under the hood. We could do this with a Material widget to preserve the ripple effect and to act like a Card widget:
Material(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
elevation: 1,
child: ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
leading: Text('Hello World'),
onTap: () => print('Pressed ListTile'),
),
),
Output:
Please change your code
Card(child: InkWell(child: ListTile(), onTab: () {},),),
First of all Card widget, its child Inkwell and then ListTile.

Flutter ListTile splash/ripple effect not matching border

I have a ListTile in flutter but I cannot seem to figure out how to make the splash/ripple effect fit the border. My border is rounded, but the splash is just a normal rectangle with no round borders, as seen on the image below.
ListTile
Below is the code for the ListTile.
Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
),
child: ListTile(
title: text(title, 0.0),
leading: Icon(
icon,
color: primaryColor,
),
)
)
You can use InkWell:
InkWell(
customBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
onTap: () {},
splashColor: Colors.red,
child: ListTile(
title: Text("Title"),
),
),
Surround Ink or InkWell with ClipRRect with border-radius value equal to
BorderRadius.all(Radius.circular(borderRadius))
Better, replace Ink with InkWell and set borderRadius: BorderRadius.all(Radius.circular(borderRadius)) which won't need clipping.
thus you can write
InkWell(
borderRadius: BorderRadius.circular(borderRadius),
onTap: () {},
splashColor: Colors.red,
child: ListTile(
title: Text("Title"),
),
),