Related
I was using a list view builder which got its item count from the hive database. I managed to get it to work but its text appeared to be in brackets for example (Apollo, Jesus) any ideas on how to fix it. as in the formatting so it would appear as apollo,jesus. FYI I opened and initiated the box on the main.dart page
here is my code, I'm still learning sorry for bad code.
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main() {
runApp(nextpage());
}
class nextpage extends StatefulWidget {
const nextpage({Key? key}) : super(key: key);
#override
State<nextpage> createState() => _nextpageState();
}
class _nextpageState extends State<nextpage> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
Icons.chevron_left,
color: Colors.black,
),
onPressed: () => Navigator.pop(context),
),
backgroundColor: Colors.yellow,
centerTitle: true,
title: Text(
'Database',
style: TextStyle(color: Colors.black),
),
),
backgroundColor: Colors.yellow[200],
body: ListView.builder(
itemCount: Hive.box('db').length,
itemBuilder: (BuildContext context, int index) {
return Container(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
Hive.box('db').values.toString(),
style: TextStyle(fontSize: 20),
),
),
],
),
);
},
),
),
),
);
}
}
I tried changing the text to Hive.box('db').values.toString but it didn't provide results
You need to open the box to receive data. You can do
void main() async {
await Hive.openBox('db');
runApp(nextpage());
}
or use FutureBuilder [.open() is a future method] before ListView.
More about using hivedb
You can see a black area around the elevated button in the given image. I want to change it and match it with the background color of the rest of the page which is Colors.grey[350] .
The flow is like this => in the main.dart I am calling the widget onboardingscreen and then displaying it with pageview.builder
The code for Main.Dart
import 'package:my_mythology/Pages/login_page.dart';
import 'package:my_mythology/Pages/on_boarding_screen.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
backgroundColor: Colors.grey,
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
),
home:
Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context,index) =>(
Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)
)
),
),
Row(
children: [
SizedBox( height: 60,
width: 60,
child: ElevatedButton(onPressed: () {},
style: ElevatedButton.styleFrom(shape: CircleBorder(),),
child: SvgPicture.asset("asset/forwardarrow.svg",fit: BoxFit.contain,),)),
],
),
],
),
);
}
}
the code for Onboardingscreen is
// ignore: camel_case_types
class Onboarding_Screen extends StatelessWidget {
final String image, title, description;
const Onboarding_Screen({
Key? key,
required this.description,
required this.image,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey[350],
body: SafeArea(
child: Column(
children: [
Spacer(),
SizedBox(
height: 400,
width: 400,
child: Image.asset(
image,
fit: BoxFit.fill,
)),
Text(title,
style: Theme.of(context).textTheme.headline5!.copyWith(
fontWeight: FontWeight.bold, color: Colors.black)),
Spacer(),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black54, fontSize: 16),
),
Spacer(),
],
)),
),
);
}
}
``
First add a Scaffold to your screen, then specify a background color.
import 'package:flutter/material.dart';
import 'onboarding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
backgroundColor: Colors.grey,
),
home: Scaffold(
backgroundColor: Colors.grey[350],
body: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index) => (const Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)),
)),
Row(
children: [
SizedBox(
height: 60,
width: 60,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
child: null,
),
),
],
),
],
),
),
);
}
}
Here is the result.
You are using scaffold inside Onboarding_Screen, therefore the outer part is missing material. You dont need to use multiple MaterialApp and use Scaffold on top level as route widget.
Mostly, you will need to follow
MaterialApp(
home: Scaffold (
body: Column(...
If you create second page, means visit using navigator , you need to use Scaffold, but not MaterialApp.
You can directly provide scaffoldBackgroundColor on MaterialApp's theme.
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.grey[350], /// direct here
),
home: Scaffold(
body: Column(
children: [
Expanded(
Your widget will
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.grey[350], /// direct here
),
home: Scaffold(
body: Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index) => (Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
))),
),
Row(
children: [
SizedBox(
height: 60,
width: 60,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
child: Text("fff")
// SvgPicture.asset(
// "asset/forwardarrow.svg",
// fit: BoxFit.contain,
// ),
)),
],
),
],
),
),
);
}
}
class Onboarding_Screen extends StatelessWidget {
final String image, title, description;
const Onboarding_Screen({
Key? key,
required this.description,
required this.image,
required this.title,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: [
Spacer(),
SizedBox(
height: 400,
width: 400,
child: Image.asset(
image,
fit: BoxFit.fill,
)),
Text(
title,
style: Theme.of(context)
.textTheme
.headline5!
.copyWith(fontWeight: FontWeight.bold, color: Colors.black),
),
Spacer(),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black54, fontSize: 16),
),
Spacer(),
],
),
);
}
}
This black background is due to the fact that Row widget with ElevatedButton is not wrapped in Scaffold. Try this in this main.dart:
import 'package:my_mythology/Pages/login_page.dart';
import 'package:my_mythology/Pages/on_boarding_screen.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
backgroundColor: Colors.grey,
),
home:
Scaffold(
backgroundColor: Colors.grey[350],
body:Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context,index) =>(
Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)
)
),
),
Row(
children: [
SizedBox( height: 60,
width: 60,
child: ElevatedButton(onPressed: () {},
style: ElevatedButton.styleFrom(shape: CircleBorder(),),
child: SvgPicture.asset("asset/forwardarrow.svg",fit: BoxFit.contain,),)),
],
),
],
),
)
);
}
}
Also in onboarding_screen.dart:
import 'package:flutter/material.dart';
import 'onboarding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: PageView.builder(
itemBuilder: (context, index) => (const Onboarding_Screen(
image: "asset/odin1.png",
title: "Learn Mythology In a Fun Way",
description:
"What's your favorite story? Mythology is full of them! Discover one of the most interesting subjects ever, including gods and goddesses, monsters and heroes. Knowledge is power, so never stop learning. From the classics to the newest stories, it's all free in My Mythology!",
)),
)),
Container(
color: Colors.grey[350],
child: Row(
children: [
SizedBox(
height: 60,
width: 60,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
),
child: null,
),
),
],
),
),
],
);
}
}```
I am currently stuck with dynamic generation of widget and its state maintenance.
This is my code.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark().copyWith(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: <Widget>[
DescriptionTextField(),
DividerAddDescription(onPressed: () => print('Add another description'))
],
),
),
),
);
}
}
class DescriptionTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white38),
child: TextField(
minLines: 1,
maxLines: null,
style: TextStyle(
fontSize: 16,
),
decoration: InputDecoration(
hintText: 'Enter description',
hintStyle: TextStyle(
fontSize: 16,
),
contentPadding: EdgeInsets.symmetric(
vertical: 10.0, horizontal: 10.0),
border: InputBorder.none,
),
),
);
}
}
class DividerAddDescription extends StatelessWidget {
DividerAddDescription({#required this.onPressed});
final Function onPressed;
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Divider(
thickness: 1,
),
),
FloatingActionButton(
onPressed: onPressed,
child: Icon(
Icons.add,
color: Color(0xFF232F34),
),
backgroundColor: Colors.orange,
),
],
);
}
}
This is how the screen looks like.
What I am trying to achieve:
when clicking on the plus button, another DescriptionTextField will be added to the Column widget.
as a new DescriptionTextField is added, if the previous DescriptionTextField has description text in it, the text should be preserved.
What I don't know how to do:
where should the description text be stored? Is it in DescriptionTextField's state? i.e. do I need to make it a Stateful widget instead?
when I have multiple DescriptionTextField, how am I supposed to store the state? e.g. the description text
You should create a List variable in your State, add the new elements there and call the setState method when adding.
class _HomeScreenState extends State<HomeScreen> {
//Create a field which hold the elements
List<DescriptionTextField> myDescriptions = List<DescriptionTextField>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: <Widget>[
...myDescriptions, //Add the elements to the Column using the spread operator
DividerAddDescription(onPressed: () => setState(() => myDescriptions.add(DescriptionTextField(key: UniqueKey()))) //Adding new widget
],
),
),
),
);
}
}
I recommend you to use a key value in your DescriptionTextField widgets, because you will be adding widget dynamically and Flutter could struggle to match the respectively their states.
There are of course many improvements, but from my perspective and what I understand from your description, this may help you.
I want to display a "Close keyboard" button above the keyboard when it is visible.
I know that the resizeToAvoidBottomInset can impact how the keyboard interact with the rest of the application, however it doesn't do exactly what I want.
I have a background image and others widgets (not shown in the sample below) which should not be resized and not moved when the keyboards is shown. This is an ok behavior when the resizeToAvoidBottomInset attribute is set to false.
However, I would like to add a button which should appear above the keyboard.
How can I do that? I only want one widget floating above the keyboard, not all the app.
Here is a sample code :
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
var home = MyHomePage(title: 'Flutter Demo Home Page');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: home,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: _getBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _getBody() {
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
}
}
Your Positioned widget has a bottom of 0, replacing with an appropriate value should do the job.
MediaQuery.of(context).viewInsets.bottom will give you the value of the height covered by the system UI(in this case the keyboard).
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
var home = MyHomePage(title: 'Flutter Demo Home Page');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: home,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: _getBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _getBody() {
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
Positioned(
bottom: MediaQuery.of(context).viewInsets.bottom,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
}
}
2022 Update
A PR was merged that provides platform-synchronized animations for closing/opening the keyboard. See the PR in effect here.
Detailed Answer
To achieve keyboard-visibility-based animated padding, here are a few modifications over #10101010's great answer:
If you want the bottom change when keyboard changes visibility to be animated AND you want extra padding under your floating child then:
1- Use keyboard_visibility flutter pub
To listen when keyboard is appearing/disappearing, like so:
bool isKeyboardVisible = false;
#override
void initState() {
super.initState();
KeyboardVisibilityNotification().addNewListener(
onChange: (bool visible) {
isKeyboardVisible = visible;
},
);
}
Optionally you can write your own native plugins, but it's already there you can check the pub's git repo.
2- Consume visibility flag in your AnimatedPostioned:
For fine-tuned animated padding, like so:
Widget _getBody() {
double bottomPadding = 0;
if (isKeyboardVisible) {
// when keyboard is shown, our floating widget is above the keyboard and its accessories by `16`
bottomPadding = MediaQuery.of(context).viewInsets.bottom + 16;
} else {
// when keyboard is hidden, we should have default spacing
bottomPadding = 48; // MediaQuery.of(context).size.height * 0.15;
}
return Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/sample.jpg"), fit: BoxFit.fitWidth)),
// color: Color.fromARGB(50, 200, 50, 20),
child: Column(
children: <Widget>[TextField()],
),
),
AnimatedPositioned(
duration: Duration(milliseconds: 500),
bottom: bottomPadding,
left: 0,
right: 0,
child: Container(
height: 50,
child: Text("Aboveeeeee"),
decoration: BoxDecoration(color: Colors.pink),
),
),
]);
}
3- Keyboard-specific animation curve and duration for synchronized animation
For now this is still an known ongoing issue
You can use the bottomSheet of a Scaffold widget.
Example:
return Scaffold(
appBar: AppBar(
title: const Text("New Game"),
),
bottomSheet: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
color: Colors.blue,
child: const SizedBox(
width: double.infinity,
height: 20,
child: Text("Above Keyboard"),
))
...
)
You can use bottomSheet parameter of the Scaffold, which keep a persistent bottom sheet. See below code.
class InputScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Close')),
bottomSheet: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
color: Colors.black,
child: const SizedBox(width: double.infinity, height: 10)),
body: Column(
children: [
const TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter your input here',
),
),
ElevatedButton(
onPressed: () {},
child: const Text('Submit'),
),
],
),
);
}
}
check this package, it can show a dismiss button above the keyboard.
I am trying to build a pokedex application in flutter. Currently I have created the first screen, with all 151 pokemon, their image, name, and # from a json api call. I am trying to make functionality where when you tap on a specific pokemon from the first screen, a new screen will appear with more details about the pokemon you tapped on. Currently having difficulties setting up my navigation to carry that information over.
Here is my project
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
Map _data;
List _pokemon = [];
void main() async {
_data = await fetchData();
_pokemon = _data['pokemon'];
runApp(
MaterialApp(
title: 'Poke App',
home: new HomePage(),
debugShowCheckedModeBanner: false,
),
);
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
fetchData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Poke App'),
centerTitle: true,
backgroundColor: Colors.cyan,
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.cyan,
child: Icon(Icons.search),
),
body: GridView.count(
crossAxisCount: 2,
children: List.generate(_pokemon.length, (index) {
return Padding(
padding: const EdgeInsets.fromLTRB(1.0, 5.0, 1.0, 5.0),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => new PokeDetails(_pokemon[index]
),
),
);
},
child: Card(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('${_pokemon[index]['img']}'),
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 2.0),
child: Text(
'${_pokemon[index]['name']}',
style: TextStyle(
fontSize: 16.0,
fontFamily: 'Chivo',
fontStyle: FontStyle.italic),
),
),
Text(
'${_pokemon[index]['num']}',
style: TextStyle(
fontFamily: 'Indie Flower',
fontWeight: FontWeight.w400,
fontSize: 20.0),
)
],
),
),
),
);
}),
));
}
}
Future<Map> fetchData() async {
String url =
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json";
http.Response response = await http.get(url);
return json.decode(response.body);
}
class PokeDetails extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.cyan,
appBar: AppBar(
title: Text('${_pokemon[index]['name']}'),
centerTitle: true,
backgroundColor: Colors.cyan,
),
);
}
}
I am expecting the correct pokemon to appear on screen 2 (PokeDetails) but i have yet to be able to achieve this
I think you may benefit from reading through some more of the documentation on flutter. Though, to get you moving forward, your PokeDetails class has no way of knowing what to look for when you're sending over the pokemon data... You should create a pokemon class so you can map the api results over to something a little easier to work with. Then you can do something like:
class PokeDetails extends StatelessWidget{
final Pokemon pokemon;
PokeDetails({
#required this.pokemon
});
//now display the pokemon details
}
Side-note, you'll want to avoid using those global variables and functions (such as fetchData, _data, and _pokemon). Those should be in their own classes. Maybe a class containing your fetch function along with a map of the data that you received. This is all kind of the bare minimum to get your feet wet. Happy coding!