I am struggling to set up the correct layout for my composite widgets.
It is the Stack widget containing two images each wrapped in the corresponding widget which are applying some visual effects on the images.
The images are supposed to change every couple of seconds and then I am using the AnimatedSwitcher to animate the fading transition between them.
This is how it looks now:
The result I want to achieve should look like this:
Here is the source code of the corresponding widget:
import 'dart:ui';
import 'package:demo_flutter_fading_images/themes/style.dart';
import 'package:flutter/material.dart';
class ImagesStack extends StatefulWidget {
final String imagePath;
const ImagesStack({required Key key, required this.imagePath}) : super(key: key);
#override
State<ImagesStack> createState() => _ImagesStackState();
}
class _ImagesStackState extends State<ImagesStack> {
#override
Widget build(BuildContext context) {
return Center(
child: Stack(children: <Widget>[
ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 6,
sigmaY: 6,
),
child: Container(
// constraints: const BoxConstraints.expand(),
constraints: BoxConstraints.tight(const Size(360, 500)),
decoration: BoxDecoration(
image: DecorationImage(
alignment: Alignment.center,
image: AssetImage(widget.imagePath),
fit: BoxFit.fill,
),
),
),
),
Container(
margin: const EdgeInsets.fromLTRB(8, 4, 8, 4),
decoration: frontImageBoxDecoration,
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
widget.imagePath,
fit: BoxFit.fill,
),
),
),
]),
);
}
}
And the full source code of demo project:
github - demo project
I tried it quickly on dartpad.
https://dartpad.dev/?id=3c24c716a9844b706662cb495675f56d
You can refer to the code to follow the structure and make changes. I have left some comments to help understand the code.
Try resizing the window after running the app in dart to see how the image gets positioned for different sizes.
Related
1. Explanation
I want to change full color of 'SizedBox' to see the location and scope of 'SizedBox'. I wonder is there any way to change SizedBox's color without filling it with Container or Decoration box. If not, I want to know how to fill SizedBox with decoration box.
2. Code
Here is a code that I tried.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home : Scaffold(
appBar: AppBar(
title : const Text('this is title'),
),
body : const SizedBox(
width : 200,
child: DecoratedBox(
decoration: BoxDecoration(
color : Colors.red,
),
),
),
bottomNavigationBar: (
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [
Icon(Icons.favorite),
Icon(Icons.home),
Icon(Icons.settings)
],
)
),
),
);
}
}
**3. Result **
Here is what I got from the code.
You can wrap your SizedBox with ColoredBox
ColoredBox(
color: Colors.cyanAccent,
child: SizedBox(
width: 200,
height: 100,),
),
You can try ColoredBox widget
SizedBox(
width : 200,
height: 20,
child: ColoredBox(color: Colors.amber),
),
If you'd like to decorate the SizedBox to see the location and scope of the Widget just for debugging purposes, we can enable the debugPaintSizeEnabled just by pressing p on the CLI upon launching the flutter run command.
Otherwise, using a Container with explicit size parameters it's mostly the same as using SizedBox, and it would allow you to use have a background color or border decoration.
Another option would be to use a ColoredBox as the child of the SizedBox, or vice versa.
I'm not sure why you'd use it but you could have the child of the SizedBox be a container with the color you want. The container will stretch to the sizes provided
SizedBox(
height: 10,
width: 30,
child: Container(color: Colors.red),
),
Also you could use the widget inspector provided by flutter:
https://docs.flutter.dev/development/tools/devtools/inspector#:~:text=The%20Flutter%20widget%20inspector%20is,%2C%20rows%2C%20and%20columns).
I have a GridView with a Scrollbar, which is behaving fine on most devices.
However, on iPhoneX (or other iPhone with a notch) when in landscape orientation only, the scrollbar floats over the top of the Gridview content rather than nicely aligning to the right of it.
If the scrollbar is oriented to the left, the same indentation happens on the left hand side.
It's almost as if flutter is applying an offset to account for the safe area of the notch, even though the container with the gridview inside it is no-where near the notch.
I can't work out a way of fixing this. Is it a bug with flutter or am I doing something wrong?
I'm seeing the same result when using a Listview or a Gridview.
On older iPhones without the notch, the issue is not present, and the scrollbar aligns as you would expect. Some on iPhoneX in portrait mode. Same on all Android phones in either orientation.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
padding: const EdgeInsets.fromLTRB(100, 10, 100, 10),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey[800]!,
blurRadius: 10,
offset: const Offset(5, 5), // Shadow position
),
],
),
child: Scrollbar(
thickness: 7,
scrollbarOrientation: ScrollbarOrientation.right,
isAlwaysShown: true,
child: GridView.count(
crossAxisCount: 3,
children: List.generate(
10,
(index) {
return Center(
child: Container(
color: Colors.redAccent[200],
margin: const EdgeInsets.all(5.0),
),
);
},
),
),
),
),
),
),
);
}
}
I'm still new to Flutter Web. I have 3 lines in my flutter web, the first line is the welcome message, the second line is a product and the last is contact, to see those lines user needs to do a scroll on my web. But how can I wrap my code using the Scroll function in flutter web? this is my code.
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
body: Column(
children: [
Container(
// Code Line 1
height: size.height,
width: size.width,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/container.jpg"),
fit: BoxFit.fitWidth),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CusAppBar(),
Spacer(),
Body(),
Spacer(
flex: 1,
),
],
),
),
Container(
// Code Line 2 Here
),
Container(
// Code Line 3 Here
)
],
),
);
}
}
My background is react, usually we just use tag ScrollView outside the container so the user can scroll the page. But how I can implement it on flutter web?
Thank you.
Try to add your fist Column inside SingleChildScrollView like below hope it help you:
body: SingleChildScrollView(
child:Column(
children:[
//Declare Your Widgets Here
],
),
),
The following code works fine to get the right container color. However, when I want to use the _green function replacing Color(0xff0c9869) in the BoxDecoration widget, the color turns out to be very pale/transparent.
It seems like the same solution, but the result is totally different, anyone knows why?
import 'package:flutter/material.dart';
class Home extends StatelessWidget {
final _green = Color(0xff0c9869);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
Container(
height: 200,
decoration: BoxDecoration(
color: Color(0xff0c9869),
borderRadius: BorderRadius.all(
Radius.circular(35),
),
),
child: Row(
children: [Text('Hi'), Icon(Icons.account_circle)],
),
)
]));
}
}
I'm trying to build a simple Flutter application that displays a full-screen background image and enables the user to drag certain widgets (i.e. a basic circle) from pre-defined start positions (given in pixels) to pre-defined target positions (also given in pixels). The following screenshot from the TouchSurgery app shows a very similar setup to what I'm trying to achieve (green circle = start position, white circle = target position):
My biggest concern at this point are different screen sizes. Let's assume we have an iPhone SE (second generation) with a resolution of 750 x 1334. I can create the following background image with the desired resolution and randomly determine the desired start position to be at coordinates (430, 949) (for simplicity we can disregard the target position):
With the following widget, I can render a circular Container on top of the starting point:
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var dpr = MediaQuery.of(context).devicePixelRatio;
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/iPhoneSE.png"),
fit: BoxFit.fill,
),
),
),
Positioned(
left: 430 / dpr,
top: 949 / dpr,
child: Container(
width: 77.0 / dpr,
height: 77.0 / dpr,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
);
}
}
The resulting image looks like this:
Things start to get tricky when I add an AppBar or a BottomNavigationBar to my application. Both Widgets have a default height of 56 pixels. Given a devicePixelRatio of 2 on the iPhone SE, I need to crop the size of my background image to 750 x 1110 for the overlay to still be accurate (1334 - 2 * 56 (AppBar) - 2 * 56 (BottomNavigationBar)).
Things get even more complicated for other devices such as the iPhone XR, where also the size of the safe area has to be considered. And for Android, there's even more different screen resolutions available.
My question now is the following: instead of creating differently sized background images for 20-30+ different screen sizes - is there a more efficient way in Flutter to draw widgets such as a circular Container at very specific screen locations that works independently of the actual screen size?
You need to get the size of the image container BEFORE positioning your Positioned Widget.
Because as you said, the screen size could change, independently of the image size (e.g. The screen is taller but has a bigger SafeArea, or has an appBar and BottomAppBar. The image could be the same size even if the screen size increased...)
Since your Positioned widget and your image Container are in the same build method, you have to use a LayoutBuilder widget to track the size of your image Container before moving on to building your Positioned widget.
Here's how:
(I've included 2 fully working examples so that you can see that the red circle keeps the same relative position to the background image, even when the image size changes. Your corrected code is the first example).
Example 1
/*
I used these calculated ratios based on your code.
Feel free to use any other way to get these ratios.
The method will be the same.
- The image takes all the available width and height
- The positioned element is postioned :
58.9% from the left of the image container
72% from the top of the image container
- The inner container's:
width is 7.129629629% of the Image Container's width,
height is 4.292084726% of the Image Container's height,
*/
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) { //This is key
return Scaffold(
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/iPhoneSE.png"),
fit: BoxFit.fill,
),
),
),
Positioned(
left: 0.589 * constraints.maxWidth,
top: 0.72 * constraints.maxHeight,
child: Container(
width: 0.07129629629 * constraints.maxWidth,
height: 04292084726 * constraints.maxHeight,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
);
});
}
}
Example 1 image:
Example 2 (with an AppBar and BottomAppBar)
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Title of app"),
),
body: LayoutBuilder(builder: (context, constraints) {
return Column(
children: <Widget>[
Flexible(
fit: FlexFit.loose,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/iPhoneSE.png"),
fit: BoxFit.fill,
),
),
),
Positioned(
left: 0.589 * constraints.maxWidth,
top: 0.72 * constraints.maxHeight,
child: Container(
width: 0.07129629629 * constraints.maxWidth,
height: 0.04292084726 * constraints.maxHeight,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
),
],
);
}),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
title: Text("Home")),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle), title: Text("Profile")),
],
),
);
}
}
Example 2 image:
How about using a Transform.scale widget on your stack and just resizing the whole thing to fit inside whatever constraints the device has?
Something like this:
Transform.scale(
alignment: Alignment.topLeft,
scale: scaleVar,
child: Stack(
children: <Widget>[
Positioned(
top: 0,
left: 0,
child: Image(
image: AssetImage("assets/iPhoneSE.png"),
alignment: Alignment.topLeft,
),
),
Positioned(
left: 430,
top: 949,
child: Container(
width: 77.0,
height: 77.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
),
),
),
],
),
)