separate class BaseLayout for background image - image

// I want to use a background image for every page in my Flutter app. For the moment, I'm using a
// separate class BaseLayout to set up the background image. However, flutter does not reflect the
// described the background image on the device.
// Is there a better way to reflect the background image?
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CarouselSlider(
options: CarouselOptions(height: 240.0),
items: [1, 2, 3, 4, 5].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(color: Colors.amber),
child: Text(
'text $i',
style: TextStyle(fontSize: 16.0),
));
},
);
}).toList(),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class BaseLayout extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/logo1.svg"), fit: BoxFit.cover),
),
child: Center(child: FlutterLogo(size: 300)),
);
}
}````

You have to make your scaffold background transparent, If you are going to use a Base Layout as a parent to all your pages.
You can use scaffoldBackgroundColor property of Scaffold widget to make it transparent.
Or better you can define it your Theme data while you declare your MaterialApp.
Sample Code:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
scaffoldBackgroundColor: Colors.transparent, // To Make scaffold background Transparent
appBarTheme: AppBarTheme(color:Colors.transparent // To Make appbar background transparent.
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Then on your BaseLayout class:
class BaseLayout extends StatelessWidget {
const BaseLayout({this.child});
final Widget child;
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/logo1.svg"), fit: BoxFit.cover),
),
child: Center(child: child),
);
}
}
Now you can wrap any Scaffold widget of your app with this BaseLayout class you just created and it's background image will be same across whole application.

Related

Identify search widget using key in widget test?

I try to create a widget test. But I can't understand how to identify widgets can find the key in the main code and do a test?
Main. dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Reversi',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var _controller;
var _reversed;
#override
void initState() {
super.initState();
_controller = TextEditingController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Reversi'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Enter string to reverse"),
),
const SizedBox(height: 10.0),
if (_reversed != null) ...[
Text(
_reversed,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
const SizedBox(height: 10.0),
],
RaisedButton(
child: Text("Reverse"),
onPressed: () {
if (_controller.text.isEmpty) return;
setState(() {
_reversed = reverseString(_controller.text);
});
},
),
],
),
),
);
}
}
String reverseString(String initial) {
return initial.split('').reversed.join();
}
This is the widget test code I created. Is this code correct to find the key in the main code and do the test?
main_widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_testing/main.dart';
import 'package:flutter_test/flutter_test.dart';
void main(){
testWidgets('Reverse string widget test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
var textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, 'Hello');
expect(find.text('Hello'), findsOneWidget);
var button = find.text("Reverse");
expect(button,findsOneWidget);
await tester.tap(button);
await tester.pump();
expect(find.text("olleH"),findsOneWidget);
});
}
How can we identify whether the widget can find the key in the main code and do a test? Can someone explain to me if this code is correct?

Changing the AppBar colour when a new tab is selected (Flutter)

I have an app with a tab bar and to make the UI better, I wanted to make it so that the colour changes when you got to another tab. How do I make it so that when I click or swipe to another tab, let's say the yellow tab, the whole appbar changes to that colour?
Code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ColorChange>(
create: (context) => ColorChange(),
child: MaterialApp(
theme: ThemeData.light(),
home: SimpleTab(),
),
);
}
}
class _TestPageState extends State<TestPage> {
TabController controller;
class ColorChange extends ChangeNotifier {
Color color = colors[0];
Color getColor() {
return color;
}
void changeColor() {
color = colors[controller.index];
print(color);
notifyListeners();
}
}
List<Color> colors = const [
Colors.green,
Colors.yellow,
Colors.red,
Colors.blue,
Colors.deepOrange,
Colors.deepPurple,
];
class SimpleTab extends StatefulWidget {
#override
_SimpleTabState createState() => _SimpleTabState();
}
class _SimpleTabState extends State<SimpleTab>
with SingleTickerProviderStateMixin {
Tester tester = Tester();
#override
void initState() {
super.initState();
controller = TabController(length: colors.length, vsync: this);
controller.addListener(ColorChange().changeColor);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Simple Tab Demo"),
backgroundColor: Provider.of<ColorChange>(context).getColor(),
bottom: TabBar(
controller: controller,
tabs: [
Tab(
text: 'Green',
),
Tab(
text: 'Yellow',
),
Tab(
text: 'Red',
),
Tab(
text: 'Blue',
),
Tab(
text: 'Orange',
),
Tab(
text: 'Purple',
),
],
isScrollable: true,
),
),
body: TabBarView(
controller: controller,
children: <Widget>[
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
Container(
// child: WidgetThing(tester: tester),
),
],
),
);
}
}
This is just a very simplified demo of my real app. My real app deals with a lot of data fetched from APIs, hence it is probably better if setstate() was not used, because re-building the whole widget may call http requests unnecessarily.
You can try this
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Demo App',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: SimpleTab(),
);
}
}
class CustomTab {
const CustomTab({this.title, this.color});
final String title;
final Color color;
}
class SimpleTab extends StatefulWidget {
#override
_SimpleTabState createState() => _SimpleTabState();
}
class _SimpleTabState extends State<SimpleTab>
with SingleTickerProviderStateMixin {
TabController controller;
List<CustomTab> tabs = const <CustomTab>[
const CustomTab(title: 'Home', color: Colors.deepOrangeAccent),
const CustomTab(title: 'Setting', color: Colors.blueGrey),
const CustomTab(title: 'Map', color: Colors.teal),
];
CustomTab selectedTab;
#override
void initState() {
super.initState();
controller = new TabController(length: tabs.length, vsync: this);
controller.addListener(_select);
selectedTab = tabs[0];
}
void _select() {
setState(() {
selectedTab = tabs[controller.index];
});
}
#override
Widget build(BuildContext context) {
textStyle() {
return new TextStyle(color: Colors.white, fontSize: 30.0);
}
return new Scaffold(
appBar: new AppBar(
title: new Text("Smiple Tab Demo"),
backgroundColor: selectedTab.color,
bottom: new TabBar(
controller: controller,
tabs: tabs
.map((e) => new Tab(
text: e.title,
))
.toList()),
),
body: new TabBarView(
controller: controller,
children: tabs
.map(
(e) => new Container(
color: e.color,
child: new Center(
child: new Text(
e.title,
style: textStyle(),
),
),
),
)
.toList()),
);
}
}

Flatbutton is invisible. It is not showing asset image on Flatbutton

it's a code of a main file
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("RTSPS"),
),
body: Center(
child: FlatButton(
child: Image.asset('assets/1st.png'),
onPressed:()=>HomePage(),
),
),
),
);
}
}
and here is pubspec.yaml file code in which I only made changes in assets
assets:
- assets/1st.png

Animate ListView item to full screen in Flutter

I would like to have my list items perform this animation (mp4) when tapped. I tried using AnimatedCrossFade but it requires its two children to be at the same level, e.g. the detail view cross-fades with the ListView not the tapped item. In fact it seems a Hero animation is the only one that can animate across widgets.
I'm having trouble using Hero. Should it wrap the list item? Does it matter if the Widget subtree is significantly different in the Hero source/destination? Also, can Hero animations be used with LocalHistoryRoutes or staggered animations?
Edit
It's now looking like what I need to do is use an Overlay, the hard part there is that I need to add the selected item to the overlay at the same position on screen where it was tapped, then the animation part would be easy. Possibly of use here is a target/follower pattern e.g. CompositedTransformTarget
You can just use Hero widget to make that kind of animation. Here's my example:
and the source code:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new FirstPage(title: 'Color Palette'),
);
}
}
class FirstPage extends StatefulWidget {
FirstPage({Key key, this.title}) : super(key: key);
final String title;
#override
_FirstPageState createState() => new _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
final palette = [
{'#E53935': 0xFFE53935},
{'#D81B60': 0xFFD81B60},
{'#8E24AA': 0xFF8E24AA},
{'#5E35B1': 0xFF5E35B1},
{'#3949AB': 0xFF3949AB},
{'#1E88E5': 0xFF1E88E5},
{'#039BE5': 0xFF039BE5},
{'#00ACC1': 0xFF00ACC1},
{'#00897B': 0xFF00897B},
{'#43A047': 0xFF43A047},
{'#7CB342': 0xFF7CB342},
{'#C0CA33': 0xFFC0CA33},
];
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Container(
child: new ListView.builder(
itemCount: palette.length,
itemBuilder: (context, index) => new Hero(
tag: palette[index].keys.first,
child: new GestureDetector(
onTap: () {
Navigator
.of(context)
.push(new ColorPageRoute(palette[index]));
},
child: new Container(
height: 64.0,
width: double.infinity,
color: new Color(palette[index].values.first),
child: new Center(
child: new Hero(
tag: 'text-${palette[index].keys.first}',
child: new Text(
palette[index].keys.first,
style: Theme.of(context).textTheme.title.copyWith(
color: Colors.white,
),
),
),
),
),
),
)),
),
);
}
}
class SecondPage extends StatelessWidget {
final Map<String, int> color;
SecondPage({this.color});
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Color'),
),
body: new Hero(
tag: color.keys.first,
child: new Container(
color: new Color(color.values.first),
child: new Center(
child: new Hero(
tag: 'text-${color.keys.first}',
child: new Text(
color.keys.first,
style:
Theme.of(context).textTheme.title.copyWith(color: Colors.white),
),
),
),
),
),
);
}
}
class ColorPageRoute extends MaterialPageRoute {
ColorPageRoute(Map<String, int> color)
: super(
builder: (context) => new SecondPage(
color: color,
));
#override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(opacity: animation, child: child);
}
}
Someone wrote an amazing dart-package for just this purpose: https://pub.dev/packages/morpheus#-readme-tab-
All you then need to do is use the MorpheusPageRoute and the package handles the rest.
...
Navigator.push(
context,
MorpheusPageRoute(
builder: (context) => MyWidget(title: title),
),
);
...
I'd just cheat and wrap the whole thing in a Stack - bottom layer would be a page with the AppBar, and the top layer would be transparent until painted on.
onTap, duplicate ListTile onto the top surface, and then a Hero animation would fill the full screen. It's not very elegant, but the framework doesn't (yet) provide for covering the AppBar easily, so having a canvas ready to be painted on for other tricky animations might be resourceful.
I'm unable to comment or edit Lucas' post (new account) but you also need to provide the parentKey of the widget where the animation is to begin:
final widgetKey = GlobalKey();
...
ListTile(
key: widgetKey,
title: Text('My ListItem'),
onTap: () => Navigator.push(
context,
MorpheusPageRoute(
builder: (context) => MyNewPage(),
parentKey: widgetKey,
),
),
),
https://pub.dev/packages/morpheus

Firebase Admob - Banner Ad overlapping the navigation drawer

After adding firebase_admob plugin and getting it up and running I noticed it overlays the fab and navigation drawer. I've fixed the fab using persistentFooterButtons but I can't seem to find a workaround for the navigation-drawer. Any help is much appreciated.
Find below a sample implementation, to recreate the issue in flutter:
import 'package:flutter/material.dart';
import 'package:firebase_admob/firebase_admob.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Firebase AdMob',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'AdMob Test App'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
BannerAd myBanner;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
super.initState();
myBanner = new BannerAd(
// Replace the testAdUnitId with an ad unit id from the AdMob dash.
// https://developers.google.com/admob/android/test-ads
// https://developers.google.com/admob/ios/test-ads
adUnitId: BannerAd.testAdUnitId,
size: AdSize.smartBanner,
targetingInfo: new MobileAdTargetingInfo(
// gender: MobileAdGender.unknown
),
listener: (MobileAdEvent event) {
print("BannerAd event is $event");
},
);
myBanner..load()..show(
// Banner Position
anchorType: AnchorType.bottom,
);
}
#override
void dispose() {
myBanner?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
drawer: new Drawer(),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('You have pushed the button this many times:'),
new Text('$_counter', style: Theme.of(context).textTheme.display1),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
I'm a little late to this but had same problem.
My nav drawer lives in a scrollable container with a fixed height so that it stops above the add and is scrollable. May not be perfect answer but works for me.
I had the same problem and my solution was the same Added by #moehagene. I added an empty item to the bottom of the drawer with the height of the Ad, so the drawer becomes scrollable when there is not enough space and the Ad is showing. I think this is reasonable. Code below:
return Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: Column(
children: <Widget>[
Expanded(
child: Container(
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
_Item1,
_Item2,
_Item3,
_Item4,
model.isShowingAds ? _emptySpaceItem : null,
],
),
),
),
],
),
);

Resources