I've recently developed comment view below the detail posts.
Like the image I attached, I'd like to show images for each comment but the image Container should be transparent to see the last comment.
But I think Scaffold doesn't allow bottomSheet to have transparent children.
Are there anyone having an idea to solve this problem?
class PostDetail extends StatelessWidget {
final int maxRenderImgCnt = 4;
final Post post;
PostDetail(this.post);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar( ... ),
body: SingleChildScrollView( ... ),
bottomSheet: CommonTextField(onTap: null, editTarget: null),
You can wrap the widget with an opacity widget but there is also another way which is more efficient even for changing it later, that is the ThemeData widget:
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.black.withOpacity(0),
),
Related
I understand that it is used to adjust AppBar, but what is PreferredSize after all?
What is the use of PreferredSize widget in flutter?
The following text is found in the official documents, but I do not understand what it means.
https://api.flutter.dev/flutter/widgets/PreferredSize-class.html
It just advertises a preferred size which can be used by the parent.
The explanation in the official documentation is also limited to the AppBar, which I could not understand further.
I wrote the following code as a test, but the height of the green container was spread across the entire screen.
import 'package:flutter/material.dart';
void main() {
runApp(const _MyApp());
}
class _MyApp extends StatelessWidget {
const _MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: PreferredSize(
preferredSize: const Size.fromHeight(100.0),
child: Container(
width: 300,
color: Colors.green,
),
),
),
),
);
}
}
Here is the Short Details about it:
Preferred Size is a custom widget lets you allow to design your custom appbar for you with the same height, width, elevation and feel similar to Appbar.
Sometimes you want to create tabs or more effective design for your appbar then you can create a customChild for your appBar with the help of PreferredSizeWidget.
The size this widget would prefer if it were otherwise unconstrained.
In many cases it's only necessary to define one preferred dimension.
For example the [Scaffold] only depends on its app bar's preferred
height. In that case implementations of this method can just return
Size.fromHeight(myAppBarHeight).
I have a big app and there's multi files with same scaffold tap action to hide the keyboard.
Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Container(
///Textfields
),
),
),
);
Is there way to edit Scaffold widget for the whole app?
short answer, you can not customize your scaffold for the whole app because each scaffold has its own body, but you can customize the theme of the app such as the text colour or the font for the whole app on the main screen using the materialApp widget.
-If you are willing to make something fixed in the whole app like the same app bar or the navbar for the whole app that's possible and you have to create a separate screen for it.
-or if you are using a customized widget a lot, Flutter let you extract it, give it a name and use it again without rewriting the whole code again but by just writing the name you chose for it
In that case you can create your custom scaffold wrapper.
class ScaffoldWrapper extends StatelessWidget {
const ScaffoldWrapper({Key? key, required this.child}) : super(key: key);
final Widget child;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
child: child,
),
),
);
}
}
Now you can replace all occurrence of your mentioned code block with this..
ScaffoldWrapper(child: Container()); // your widget contents
I am trying to perform basic widget testing in Flutter. Basically I would like to have a list with list of data, and display each of the items in a custom widget (BasicListItem) which also has a ListTile widget in it.
Root widget:
class MyApp extends StatelessWidget {
final List taskList = ['List-1', 'List-2', 'List-3'];
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: ListView.builder(
itemCount: taskList.length, itemBuilder: _itemBuilder),
),
);
}
Widget _itemBuilder(BuildContext context, int index) {
final String item = taskList[index];
return BasicListItem(key: Key(item), title: item);
}
}
The list item widget (BasicListItem) takes a title, and use it inside the ListTile widget.
class BasicListItem extends StatelessWidget {
final String title;
const BasicListItem({required Key key, required this.title})
: super(key: key);
#override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(Icons.map),
title: Text(title),
);
}
}
This is the test for it:
testWidgets('has title and Icons', (WidgetTester tester) async {
const testKey = Key('my-key-1');
const testTitle = 'Demo title';
await tester.pumpWidget(BasicListItem(key: testKey, title: testTitle));
expect(find.text(testTitle), findsOneWidget);
});
But the test throws an error:
No Material widget found. ListTile widgets require a Material widget
ancestor.
...
...
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree Actual:
_TextFinder:<zero widgets with text "Demo title" (ignoring offstage widgets)>
However, the test does pass if I wrap ListTile around a MaterialApp, inside the BasicListItem build method. Like so:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: title,
home: Scaffold(
body: ListTile(
leading: Icon(Icons.map),
title: Text(title),
),
)
);
}
But doing this I cannot use it inside the ListView widget. And also I would like to have modular/separate custom widgets so that I can use it on different places as well. I am new and maybe I am missing something. How can I build custom widget and test it out? Could you help me out please.
I didn't understand Darshan's answer at first, because I think the code he provided made me implement the MaterialApp and Material widget into BasicListItem widget class build method directly, instead of implementing it on just the test suit. But that gave me the clue to implement it.
So, this is the final test case. I did wrapped MaterialApp and Material widget with BasicListItem, but not in the build method, instead I wrapped them just on the test case:
testWidgets('has title and Icons', (WidgetTester tester) async {
const testKey = Key('my-key-1');
const testTitle = 'Demo title';
await await tester.pumpWidget(MaterialApp(
home: Material(
child: BasicListItem(key: testKey, title: testTitle),
),
));;
expect(find.text(testTitle), findsOneWidget);
});
I hope this will help others like me as well.
The ListTile component comes from the Material part of Flutter UI components & is not an independent widget, therefore it needs a MaterialApp as parent.
You can check that the ListTile is under material library here: https://api.flutter.dev/flutter/material/ListTile-class.html
Also, you can create as many custom Widgets to use in separate modules,
the only requirement would be to use MaterialApp at the very beginning of the app initialisation.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
/// Only this needs to be a MaterialApp
return MaterialApp(
title: 'Welcome to Flutter',
/// this point to different screen widget also, like MainScreen()
/// Or you can start using Scaffold from here as well.
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Hello World'),
),
),
);
}
}
It is not necessary to use MaterialApp as a parent on every custom widget you build. Just the root can be fine too.
But if you are using a single widget to simply test out, & it requires a Material ancestor, you can simply wrap the widget in a Material widget as well.
Okay, this is not specifically in Flutter Docs but is hinted about all over the place. On flutter test side we are pumping a root widget to render a frame as our palette used to test widgets.
Translates to you need to create a Root App Widget to wrap the widget under test. eBay's Golden Toolkit supplies the hooks to make this possible via pumpWidgetBuilder which is an extension of Widget Tester.
For more see my blog, https://fredgrott.medium.com
I want to use MediaQuery to build widgets based on screen height and width. The problem, also referenced in #26004, is that I only want to query the size data once, for example in initState. MediaQuery documentation states
Querying the current media using MediaQuery.of will cause your widget to rebuild automatically whenever the MediaQueryData changes (e.g., if the user rotates their device).
, but that causes unnecessary rebuilds in my application. Specifically, it causes rebuild of widgets if there are changes to insets or padding (such as when keyboard is displayed).
Is there an alternative to MediaQuery which wouldn't cause rebuilds when MediaQueryData changes?
I had this issue as well and initially thought that the MediaQuery is causing unnecessary rebuilds, but if you think about it you do want the widgets to rebuild (in cases of device rotation, keyboard popup) for the app to have a responsive design.
You could do something like this:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Builder(builder: (context) {
ResponsiveApp.setMq(context);
return 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: Flex(
direction:
ResponsiveApp().mq.size.width > ResponsiveApp().mq.size.height
? Axis.horizontal
: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ResponsiveApp {
static MediaQueryData _mediaQueryData;
MediaQueryData get mq => _mediaQueryData;
static void setMq(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
}
}
I set the mediaQueryData at the beginning with ResponsiveApp.setMq(context) and I used the Builder because you can only use the MediaQuery one context below the MaterialApp widget. After the _mediaQueryData is set you can get it whenever you want to build widgets based on the screen size.
In this code I just change the Axis direction when the device is rotated and the widget needs to rebuild to show the changed direction.
You could also have something like :
if (_mediaQueryData.size.shortestSide < 400)
//phone layout
else if(_mediaQueryData.size.shortestSide >= 400 && _mediaQueryData.size.shortestSide < 600)
//tablet layout
else
//web layout
and resizing the window in web will cause the widgets to rebuild multiple times and display the desired layout.
But if you don't want to use MediaQuery at all, you can check the Window class from dart:ui.
LayoutBuilder seems preferable over every use of MediaQuery for sizing a viewport (either the whole screen, or the space left in a column or other layout).
LayoutBuilder also works hard to avoid rebuilding its child if the size doesn't change and the parents haven't had to re-layout.
The builder function is called in the following situations:
The first time the widget is laid out.
When the parent widget passes different layout constraints.
When the parent widget updates this widget.
When the dependencies that the builder function subscribes to change.
The builder function is not called during layout if the parent passes
the same constraints repeatedly.
And you don't have to think about "the height of the appbar" ever again, because you're getting the space left, not the total space on the screen.
Check it out: https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html
In my case, the problem was happening because I was controlling the focus manually using:
onEditingComplete: () {
FocusScope.of(context).nextFocus();
}
The context used was the Parent's context, and it was causing the rebuilding. Not sure why it happened, but it stopped once I've wrap the TextFormField with a Builder and started using its context instead.
Note: I'm also using MediaQuery.of(context).size.height normally (without the rebuild side effect) to set the Widget's Parent height 🤔
Screenshot of the code and it's result:
Hi, I have StatelessWidget which has Container returning in its build method and the Text widget as a child widget. But it's look and feel is not as expected. Why is the yellow underline and how can I remove it?
I tried replacing the Container with Stack, Column and Row nothing change.
Because of you havent wrap your Text widget with a material widget. You can wrap with a Scaffold or with Material widget with color property as you want.
Example:
Scaffold(body: Center(child: Text("Here is the text")))
or:
Material(color: Colors.white, child: Center(child: Text("Here is the text")))
Every screen should have a scaffold widget
#override
Widget build(BuildContext context) {
return Scaffold(
body:Container(
child:Text("your text"),
),
);