how to make a stack widget take full screen on ios in flutter - flutter

I am trying to make an audio player app,
and I want to make the player screen fit the whole screen size.
However, the padding at the top and at the bottom doesn't help.
I tried to remove the SafeArea from bottomNavigationBar and other widgets and it didn't work.
How can I handle this?
Image of the player:
(the gray color padding doesn't let the image stretch to the end)
the code of the player:
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff1c1c1e),
body: GetBuilder<OverlayHandler>(
builder: (getContext) {
if (!Get.find<OverlayHandler>().inPipMode) {
return Stack(
children:[
Container(...)
]
); // player at full screen
} else {
return Stack(...); // player at PiP mode
}
}
)
);
}
the code of the main screen widget:
Widget build(BuildContext context) {
return GetBuilder<NavigationController>(
builder: (controller) {
return Scaffold(
body: SafeArea(
// bottom option of this SafeArea doesn't affect the player size
child: IndexedStack(
index: controller.tabIndex,
children: const [
...
],
),
),
bottomNavigationBar: SafeArea(
// bottom option of this SafeArea doesn't affect the player size
child: SizedBox(
height: 80,
child: BottomNavigationBar(
items: [
...
],
),
),
),
);
}
);
}
}

import 'package:flutter/material.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(
primarySwatch: Colors.blue,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
#override
State<HomeScreen> createState() => _HomeScreenState();
}
TextEditingController controller = TextEditingController();
bool hasHash = false;
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
height: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
"https://cdn.pixabay.com/photo/2016/09/10/11/11/musician-1658887_1280.jpg",
),
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
height: 300,
width: double.infinity,
color: Colors.black.withOpacity(.7),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Icon(
Icons.skip_previous_rounded,
size: 55,
color: Colors.white,
),
Icon(
Icons.play_circle_fill_rounded,
size: 110,
color: Colors.white,
),
Icon(
Icons.skip_next_rounded,
size: 55,
color: Colors.white,
),
],
),
),
),
],
),
);
}
}
Android screenshot
iOS screenshot

Try removing the Scaffold()'s background color and add extendBody: true, or set the height of the container to height: double.infinity, or inside the stack just add and empty container with height as height: double.infinity,

Related

How to make Column scrollable when overflowed but use expanded otherwise

I am trying to achieve an effect where there is expandable content on the top end of a sidebar, and other links on the bottom of the sidebar. When the content on the top expands to the point it needs to scroll, the bottom links should scroll in the same view.
Here is an example of what I am trying to do, except that it does not scroll. If I wrap a scrollable view around the column, that won't work with the spacer or expanded that is needed to keep the bottom links on bottom:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
#override
State<MyWidget> createState() {
return MyWidgetState();
}
}
class MyWidgetState extends State<MyWidget> {
List<int> items = [1];
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
setState(() {
items.add(items.last + 1);
});
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
if (items.length != 1) items.removeLast();
});
},
),
],
),
for (final item in items)
MyAnimatedWidget(
child: SizedBox(
height: 200,
child: Center(
child: Text('Top content item $item'),
),
),
),
Spacer(),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all()),
height: 200,
child: Text('Bottom content'),
)
],
);
}
}
class MyAnimatedWidget extends StatefulWidget {
final Widget? child;
const MyAnimatedWidget({this.child, Key? key}) : super(key: key);
#override
State<MyAnimatedWidget> createState() {
return MyAnimatedWidgetState();
}
}
class MyAnimatedWidgetState extends State<MyAnimatedWidget>
with SingleTickerProviderStateMixin {
late AnimationController controller;
#override
initState() {
controller = AnimationController(
value: 0, duration: const Duration(seconds: 1), vsync: this);
controller.animateTo(1, curve: Curves.linear);
super.initState();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, child) {
return SizedBox(height: 200 * controller.value, child: widget.child);
});
}
}
I have tried using a global key to get the size of the spacer and detect after rebuilds whether the spacer has been sized to 0, and if so, re-build the entire widget as a list view (without the spacer) instead of a column. You also need to listen in that case for if the size shrinks and it needs to become a column again, it seemed to make the performance noticeably worse, it was tricky to save the state when switching between column/listview, and it seemed not the best way to solve the problem.
Any ideas?
Try implementing this solution I've just created without the animation you have. Is a scrollable area at the top and a persistent footer.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("My AppBar"),
),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
// Your scrollable widgets here
Container(
height: 100,
color: Colors.green,
),
Container(
height: 100,
color: Colors.blue,
),
Container(
height: 100,
color: Colors.red,
),
],
),
),
),
Container(
child: Text(
'Your footer',
),
color: Colors.blueGrey,
height: 200,
width: double.infinity,
)
],
),
),
),
);
}
}

How to positioned widget toLeftOf or toRightOf in Flutter

I first want to center one widget and then add another widget to the right of the center widget.
Currently, flutter APIs are not feasible for this. In android, it can be easily done in relative layout or constraint layout.
I tried with some hack with MediaQuery,
Stack(
children: [
Center(child: Text(17)),
Positioned(
bottom: 0,
left: (screenWidth / 2) + (screenWidth / 3),
child: Column(
children: []
)
)
How to try this in an easy way or a proper way.
You can use the Align widget for this.
Code Example
import 'package:flutter/material.dart';
class SandBox extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 300,
height: 300,
color: Colors.blue,
child: Align(
alignment: Alignment.centerRight, //aligns the child widget to the right center
child: Text('17'),
),
),
),
);
}
}
Maybe, it can help you to achieve what you want:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text('17'),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
width: 10,
height: 10,
decoration: BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
),
),
],
),
);
}
}
Or you can adjust it using some calculations using MediaQuery and Stack.
You can use badges package to achieve this goal.
Finally, I found used https://pub.dev/packages/align_positioned
AlignPositioned.relative(
Text(day.englishDate.toString(),
textScaleFactor: 3, style: dayTextStyle),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
....
],
),
moveByChildWidth: 1.1,
minChildWidthRatio: 1,
moveByChildHeight: 0.3)
Please use Align along with Row.
here is simple code to achieve this.
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Stack(
children:[
Align(
child : Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Padding(child: Text('Left'),padding: EdgeInsets.all(5)),
Text('Center widget'),
Padding(child: Text('Right'),padding: EdgeInsets.all(5))
]) ,
alignment: Alignment.center),
]
),
),
);
}
}
Here is the output:

Flutter - CircleAvatar with dynamic radius according to available space

I'd like the CircleAvatar to take a specific percentage (e.g. 50%) of the available space instead of specifying a fixed radius. How would you approach that?
I am not sure this is the best solution.
You can use LayoutBuilder to get the max constraints then build according to it.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
color: Colors.red,
height: 100.0,
width: 100.0,
child: _buildCircleAvatar(),
),
Container(
color: Colors.green,
height: 300.0,
width: 300.0,
child: _buildCircleAvatar(),
),
],
),
);
}
Widget _buildCircleAvatar() {
return LayoutBuilder(
builder: (context, constraints) {
final radius = min(constraints.maxHeight / 4, constraints.maxWidth / 4);
return Center(
child: CircleAvatar(
radius: radius,
backgroundImage: NetworkImage(
"https://as.ftcdn.net/r/v1/pics/7b11b8176a3611dbfb25406156a6ef50cd3a5009/home/discover_collections/optimized/image-2019-10-11-11-36-27-681.jpg",
),
),
);
},
);
}
}
Container(
color: Colors.green,
height: MediaQuery.of(context).size.height/2,
width: MediaQuery.of(context).size.width/2 ,
child:CircleAvatar(),
)
you can use this to get the responsive avatar

Text and Image together in a Flutter Card

I want to add an image and a text together in a card but I'm not able to do it. I think a row would be used here but not able to implement it. I'm new to flutter and app development so having some troubles. Any help is really appreciated. Also the cards are in GridView(not in ListView).
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'lists.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Just Another App',
home: Home(),
routes: {
"/webview": (_) => WebviewScaffold(
withJavascript: true,
withLocalStorage: true,
url: 'https://www.google.com/',
appBar: AppBar(
title: Text('Browser'),
),
),
},
theme: ThemeData(primaryColor: Colors.black),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final webView = FlutterWebviewPlugin();
#override
void initState() {
super.initState();
webView.close();
}
#override
Widget build(BuildContext context) {
var gridView = GridView.builder(
itemCount: 15,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Card(
elevation: 10,
child: Padding(
padding: const EdgeInsets.all(35),
child: Container(
// child: SizedBox(child: Text('yashjha'),),
// child: Image.asset('lib/images/${images[index]}'),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/${images[index]}'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
),
),
),
onTap: () {
setState(() {
Navigator.of(context).pushNamed('/webview');
});
},
);
});
return Scaffold(
appBar: AppBar(
title: Text('Just Another App'),
),
body: Container(
child: gridView,
padding: EdgeInsets.all(12),
),
);
}
[GridViewApp Screenshot][1]}
This is a variable which I'm using in the "body" of Scaffold.
If you want to place an Image and a text side by side, add a Row widget:
child: Row(
children: <Widget>[
DecorationImage(...),
Text(...),
],
)
You can also set mainAxisAlignment and crossAxisAlignment to make sure that your widgets are placed correctly
just wrap your Container into a Row Widget and add a text to it.
Row(
children: <Widget>[
Text("add text here"),
Container(
// child: SizedBox(child: Text('yashjha'),),
// child: Image.asset('lib/images/${images[index]}'),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('lib/images/${images[index]}'),
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
),
],
),

Make only one widget float above the keyboard in Flutter

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.