I'm trying to create a grid of images with a 'Share' button in the top-right corner of each image. The problem is the ink splash from the IconButton doesn't extend beyond the image border. Also, it seems that there is both an ink splash on the IconButton AND an ink splash in the InkWell - there should only be one splash on the button.
I know that the ink splash is rendered on the Material layer, but I cannot seem to get that layer beyond the bounds of the image. Can anyone suggest how to do this?
Here's a screenshot:
Here's the code:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
_buildGrid() {
List<String> imgs = [
"https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Three_Sisters_Sunset.jpg/1280px-Three_Sisters_Sunset.jpg",
"https://upload.wikimedia.org/wikipedia/commons/c/c0/Opera_House_and_ferry._Sydney.jpg",
"https://upload.wikimedia.org/wikipedia/commons/b/b0/State_Library_of_New_South_Wales_Reading_Room_2017.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Sydney_Harbour_Bridge_from_Circular_Quay.jpg/2880px-Sydney_Harbour_Bridge_from_Circular_Quay.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Amptower_centerpoint.jpg/800px-Amptower_centerpoint.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/4/49/Summer_at_Manly_Beach.jpg/2560px-Summer_at_Manly_Beach.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Glasshouse.JPG/2560px-Glasshouse.JPG"
];
return new GridView.extent(
primary: true,
padding: const EdgeInsets.all(20.0),
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
maxCrossAxisExtent: 200.0,
childAspectRatio: 210.0 / 130.0,
children: imgs.map((id) => _buildThumbnail(id)).toList(),
);
}
_buildThumbnail(String url) {
return new Container(
decoration: new BoxDecoration(
border: new Border.all(
color: Colors.black45,
width: 1.0,
),
),
child: new Stack(
fit: StackFit.expand,
children: <Widget>[
new Center(
child: new Icon(
Icons.image,
color: Colors.black45,
),
),
new Image.network(
url,
fit: BoxFit.cover,
key: new Key("thumnail-$url"),
gaplessPlayback: false,
),
new Material(
type: MaterialType.transparency,
child: new InkWell(
onTap: () => print("Open image: $url"),
child: new Align(
alignment: FractionalOffset.topRight,
child: new IconButton(
splashColor: Colors.red,
icon: new Icon(Icons.share),
onPressed: () => print("Share image: $url"),
color: Colors.black87),
),
),
),
],
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Grid Splash',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('Grid Splash'),
),
body: _buildGrid(),
),
);
}
}
Use an InkResponse widget to encapsulate the button widget.
Edit: Don't forget the enableFeedback attribute.
new InkResponse(splashColor: someColor,
enableFeedback: true,
child: new IconButton(...)
)
Related
What is the best way to get a responsive svg image, I thought about using MediaQuery, but probably not quite it will fit for every screen.
I used Stack and Positioned because I have more things to lay on one screen that will overlap.
I want to make responsive this:
class Shape extends StatelessWidget {
static Route route() {
return MaterialPageRoute<void>(builder: (_) => Shape());
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
body: _profilePage(context),
);
}
Widget _profilePage(BuildContext context) {
return SafeArea(
child: Align(
child: Center(
child: Stack(children: <Widget>[
Positioned(
width: MediaQuery.of(context).size.width * 1,
height: MediaQuery.of(context).size.height,
top: MediaQuery.of(context).size.width * 0.4,
child: _curved(context),
),
]),
),
),
);
// });
}
Widget _curved(BuildContext context) {
return SvgPicture.asset(
'assets/images/shape_curved.svg',
color:Colors.green,
allowDrawingOutsideViewBox: true,
);}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
Flexible(
flex: 2,
child: Container(
color: Colors.yellow,
child: Container(
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(80.0),
))),
),
),
Flexible(
child: Container(
color: Colors.green,
child: Container(
decoration: BoxDecoration(
color: Colors.yellow,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(80.0),
))),
),
),
]),
);
}
}
Click here for picture
hi everyone, i need help making my profile page in flutter look like the image above. im not really know how make it bc there so much details in it.
this is the code i make so far:
import 'package:flutter/material.dart';
void main() => runApp(new UserDetails());
class UserDetails extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'User Details',
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.green,
leading: Icon(Icons.arrow_back),
title: Text('Edward',
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
Icon(Icons.more_vert, color: Colors.white,),
],
),
body: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
children: <Widget>[
Container(
height: 200.0,
color: Colors.green,
child: Center(
child: Icon(Icons.person, size: 250.0 ),
),
)
],)
]
),
),
);
}
}
You can achieve that adding a border radius to the Container, then use a Column to position and arrange your texts: a Column widget in this case. You need, also, set theAppBar in the Scaffold to same background color which Container has, and set elevation to zero to avoid the shadow over the containter, if you need help with this latter, let me know.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 260,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(25),
bottomRight: Radius.circular(25),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.grey,
child: Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.people, size: 50),
),
radius: 35,
),
Text("#edward"),
Text("email#email.com"),
Text("No: 00X-XXX-XXX"),
],
),
);
}
}
After watching a tutorial video about creating a custom PageView in Flutter, I've come across a problem.
In order to achieve a custom PageView's page positions, I've used a stack of items that swipe left/right depending on the PageView that is placed in a Stack.fill() above every other element in the Stack.
Here's the example of the code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test')),
body: Container(
height: 200.0,
child: Stack(
children: <Widget>[
Container(
color: Colors.blueGrey,
width: double.infinity,
height: double.infinity,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () {
print('InkWell tapped');
},
),
),
),
Positioned.fill(
child: PageView.builder(
itemBuilder: (context, index) {
return Container(
child: Center(
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
),
);
},
itemCount: 4,
),
),
],
),
),
);
}
}
The problem is that I want to trigger a Tap event on the InkWell behind the PageView, while still be able to swipe the PageView.
Is it possible to pass the tap event to the element behind the PageView?
Thanks.
EDIT:
Since you should not extend widgets in flutter, I've just made a copy of Scrollable class that uses a HitTestBehavior.translucent instead of HitTestBehavior.opaque. After that you create a copy of PageView using this new Scrollable.
With such modification - the children behind the PageView start receiving gestures.
SOLUTION:
Since you should not extend widgets in flutter, I've just made a copy of Scrollable class that uses a HitTestBehavior.translucent instead of HitTestBehavior.opaque. After that you create a copy of PageView using this new Scrollable.
With such modification - the children behind the PageView start receiving gestures.
This one is without using a stack,
Scaffold(
appBar: AppBar(title: Text('Test')),
body: Container(
color: Colors.red,
height: 200.0,
child: InkWell(
onTap: () {
print('InkWell tapped');
},
child: PageView.builder(
itemCount: 4,
itemBuilder: (context, index) {
return Container(
child: Center(
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
),
),
),
);
},
),
),
),
),
I want to blur the background of BottomNavigationBar of a scaffold, so that it can give cool blur effect of items behind it. How can I do that?
More Info: I've tried adding opacity to canvasColor by creating a new theme to the BottomNaviagtionBar. This is my code:
bottomNavigationBar: new Theme(
data: Theme.of(context).copyWith(
canvasColor: Color(0xff424242).withOpacity(0.5),
),
child: new BottomNavigationBar(
onTap: navigationTapped,
currentIndex: _page,
items: [
new BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text('Home')
),
new BottomNavigationBarItem(
icon: new Icon(Icons.dashboard),
title: new Text('Menu')
),
new BottomNavigationBarItem(
icon: new Icon(Icons.date_range),
title: new Text('Dates')
)
],
),
)
And this is output I'm getting:Image
Surprisingly, as you can see, the opacity is not at all applied. I actually don't want the BottomNavigationBar to be opaque. I want it to be blurred so that the content behind it can be viewed as blurred on the BottomNaviagtionBar. I've tried also to wrap BottomNavigationBar inside ImageFilter.blur(), But that also didn't work.
For this to work I had to place the bottom navigation in a stack with the other content of the screen. I used combination of ClipRect, BackdropFilter and Opacity. This is the working solution:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(context),
body: Stack(
//these are the screens that will be loaded for every bottom nav item
children: <Widget>[
IndexedStack(
index: _currentTab,
children: _pages,
),
_buildBottomNavigation()
],
),
);
}
Widget _buildBottomNavigation() => Align(
alignment: FractionalOffset.bottomCenter,
//this is very important, without it the whole screen will be blurred
child: ClipRect(
//I'm using BackdropFilter for the blurring effect
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10.0,
sigmaY: 10.0,
),
child: Opacity(
//you can change the opacity to whatever suits you best
opacity: 0.8,
child: BottomNavigationBar(
currentIndex: _currentTab,
onTap: (int index) {
setState(() {
_currentTab = index;
});
},
type: BottomNavigationBarType.fixed,
unselectedItemColor: AppColors.colorBlack,
items: allRoutes.map((NavigationRoute route) {
return _buildBottomNavigationBarItem(route);
}).toList(),
),
),
),
),
);
** just set a transparent backgroundColor .**
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
backgroundColor: Colors.transparent,
border: Border.all(
width: 0.0,
style: BorderStyle.none,
),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 20.0,
top: 0.0,
right: 20.0,
),
height: 280.0,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: Const.color.linearColors,
),
// image: DecorationImage(
// image: AssetImage('assets/image/bac.png'),
// ),
),
child: Row(
children: <Widget>[Text('Hello')],
),
),
),
/// end of Expanded
],
),
],
),
);
You could just wrap your BottomNavigationBar with a Backdropfilter and then wrap all with a ClipRRect. Last but not least set the Scaffold attribute extendBody to true,
bottomNavigationBar: ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 3, sigmaY: 3),
child: BottomNavigationBar(
YOUR CODE HERE
I'm writing a Flutter app, and I'd like to use/implement the "frosted glass" effect that's common on iOS. How do I do this?
You can use the BackdropFilter widget to achieve this effect.
import 'dart:ui';
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new FrostedDemo()));
}
class FrostedDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Stack(
children: <Widget>[
new ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: new FlutterLogo()
),
new Center(
child: new ClipRect(
child: new BackdropFilter(
filter: new ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: new Container(
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.5)
),
child: new Center(
child: new Text(
'Frosted',
style: Theme.of(context).textTheme.display3
),
),
),
),
),
),
],
),
);
}
}
I think I don't know the exact meaning of 'Frosted'(If my example didnot work here),
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
void main() => runApp(
MaterialApp(
title: "Frosted glass",
home: new HomePage()
)
);
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Stack(
fit: StackFit.expand,
children: <Widget>[
generateBluredImage(),
new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
rectShapeContainer(),
],
),
],
),
);
}
Widget generateBluredImage() {
return new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/images/huxley-lsd.png'),
fit: BoxFit.cover,
),
),
//I blured the parent container to blur background image, you can get rid of this part
child: new BackdropFilter(
filter: new ui.ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
child: new Container(
//you can change opacity with color here(I used black) for background.
decoration: new BoxDecoration(color: Colors.black.withOpacity(0.2)),
),
),
);
}
Widget rectShapeContainer() {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 10.0),
padding: const EdgeInsets.all(15.0),
decoration: new BoxDecoration(
//you can get rid of below line also
borderRadius: new BorderRadius.circular(10.0),
//below line is for rectangular shape
shape: BoxShape.rectangle,
//you can change opacity with color here(I used black) for rect
color: Colors.black.withOpacity(0.5),
//I added some shadow, but you can remove boxShadow also.
boxShadow: <BoxShadow>[
new BoxShadow(
color: Colors.black26,
blurRadius: 5.0,
offset: new Offset(5.0, 5.0),
),
],
),
child: new Column(
children: <Widget>[
new Text(
'There\'s only one corner of the universe you can be certain of improving and that\'s your own self.',
style: new TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
],
),
);
}
}
Outcome:
I hope this will help someone.
BackdropFilter(
filter: ImageFilter.blur(sigmaX: _sigmaX, sigmaY: _sigmaY),
child: Container(
color: Colors.black.withOpacity(_opacity),
),
),