Flutter: How to make the below image widget functional in Stack - flutter

I try to achieve the feature: pinch to zoom in/out an image under another overlay image.
My approach is using photo_view to make the main photo zoomable and put the overlay image on top of the main photo by the "stack".
import 'package:photo_view/photo_view.dart';
class Body extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: <Widget>[
Container(
child: PhotoView(
initialScale: PhotoViewComputedScale.covered,
imageProvider: AssetImage("assets/mainphoto.jpg"),
),
),
),
Container(
child: Center(
child: AssetImage("assets/overlay.png”),
),
),
],
),
);
}
}
The result of the above code
But the overlay image completely disables the main photo, I cannot pinch to zoom in/out the main photo.
I think it’s because of Stack, I googled around it but still don’t have any proper solution.
If any suggestions, I am very appreciated.

Use IgnorePointer Widget
IgnorePointer(
child: Container(
child: Center(
child: Image.asset(
"assets/overlay.png",
),
),
),
)

Related

Flutter Card child content height is larger than its parent

I'm trying to use a GridView to handle displays for multiple Card, each Card contains of an Image. Unfortunately it turns out that the Image is taking a larger height than its parent (see attached picture for the details).
I'm pretty new to Flutter layout so any ideas why this is happening and how I can resolve this? I want the layout to be something like this:
Display 2 cards on each line.
The Card width or height should not be fixed.
The Image height should be scaled according to its width.
class SquadSelectionScreen extends StatelessWidget {
final List<Team> teams;
const SquadSelectionScreen({super.key, required this.teams});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Squads'),
),
body: GridView.count(
crossAxisSpacing: 10,
crossAxisCount: 2,
padding: const EdgeInsets.all(16),
children: teams
.map(
(team) => SquadView(team: team),
)
.toList(),
),
);
}
}
class SquadView extends StatelessWidget {
final Team team;
const SquadView({super.key, required this.team});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
context.push('/squads/${team.code}');
},
child: Card(
elevation: 1,
child: Column(
children: [
Image(
image: NetworkImage(team.imageUrl),
),
const SizedBox(
height: 8,
),
Center(
child: Text(team.name),
),
],
),
),
);
}
}
Using GridView.count has a very visible drawback, namely the size of the aspect ratio of the grid will always be one (1:1 or Square) and can't be changed.
So if you look at the code above, you can't set an image with the same aspect ratio because the text will sink.
The first suggestion for me if you still want to use GridView.count is
Wrapping your Image with AspectRatio that has value higher than one (example set Ratio to 4/3, 5/3, 16/9, or landscape looks). Note: 4/3 = is higher than 1, 16/9 = is higher than 1, etc..
Then wrap the Text Widget with Expanded()
Example code:
class SquadView extends StatelessWidget {
final Team team;
const SquadView({super.key, required this.team});
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Card(
elevation: 1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
AspectRatio(
aspectRatio: 4/3, // you can set the value to 16/9 or anything that result is higher than one
child: Image(
image: NetworkImage(team.imageUrl),
fit: BoxFit.cover, // set How the image looks to Fit
),
),
const SizedBox(
height: 8,
),
Expanded(
child: Center(
child: Text(team.name, overflow: TextOverflow.ellipsis),
),
),
],
),
),
),
);
}
}
I suggest you try GridView.builder or another GridView. You can look at the documentation here
or this third package this will be good for to try flutter_staggered_grid_view. The flutter_staggered_grid_view is more flexible to create GridView with various size.

Flutter how set background on fix size

I need help. At the moment I'm trying to implement a background on my login page.
My problem is that I use a custom shape painter which shows my background.
To make my login page more dynamic I have added a function resizeToAvoidBottomInset: true, to move the textfield over the keyboard.
But now I have the problem that my background will be smaller if I click on my text field.
Here is my login page:
My code:
class _DebugPage extends State<DebugPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: customSubAppBar('Debug', context),
body: Stack(
children: [
//my custom shape painter
Expanded(
child: CustomeShapePainer(),
),
//my custom widgets
_body(context),
],
),
);
}
}
Is there a way to set the background on fix size?
I think you can try set widget CustomeShapePainer wrap Widget Stack. I don't remember exactly but in some projects I did
child: SingleChildScrollView(
child: Container(
color: AppConstants.bgColor,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: CustomPaint(
painter: CurvePainter(),
child: Stack

How to rotate a larger-than-screen image without the overflow being clipped off in Flutter?

I have this image that I would like to display full screen and rotate in the background:
Here it is filling the screen correctly:
The problem is, when it rotates, the sides have been clipped off:
I've tried every type of box fit. I've tried sizing the container width to double.infinity. I've tried wrapping the image in a SingleChildScrollView. I've tried putting overflow: Overflow.visible on the stack. All day trying things, but nothing seems to be working.
The image needs to continuously fill the screen while rotating. How can I code it so that the edges aren't clipped off?
Here's my code:
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Stack(
children: <Widget>[
SpinPerfect(
infinite: true,
duration: Duration(seconds: 10),
child: Image.asset(
'assets/images/star-burst.png',
fit: BoxFit.none,
),
),
Container(
child: Center(
child: Text('This is Screen 1'),
),
),
],
),
),
);
}
}
Note: I am currently rotating it using SpinPerfect from the animate_do package, but the same clipping problem happens when using Transform.rotate.
Thanks in advance for any direction!
Here is a solution that works very well:
Use SpinPerfect from the animate_do package (https://pub.dev/packages/animate_do) in combination with the photo_view package (https://pub.dev/packages/photo_view).
SpinPerfect(
infinite: true,
spins: 1,
duration: Duration(seconds: 60),
child: PhotoView(
disableGestures: true,
backgroundDecoration: BoxDecoration(color: Colors.transparent),
initialScale: PhotoViewComputedScale.covered * 2.7,
imageProvider: AssetImage('assets/images/background.jpg'),
),
)
Thanks to the creator of the animate_do package for the idea. (Very cool dude!)

How do I place my widget in the top Center location using Media Query in Flutter?

I have the following dial located at the center of my screen.
I have called three different part to construct this dial.
However it seems to be stuck in the center of my screen and I want to shift it to the top center portion. Ive tried changing the alignments but it doesn't seem to work.
This is my code:
This is the dependency I'm using: https://pub.dev/packages/flutter_neumorphic
import 'package:flutter_neumorphic/flutter_neumorphic.dart';
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
pedometerOuterDial(context),
pedometerInnerDial(context),
Center(child: stepText()),
],
);
}
Widget stepText() {
return Text(
'4800\nSteps',
style: khomeStyle.copyWith(color: kOrange),
);
}
Widget pedometerOuterDial(context) {
final percentage = 30.0;
return Padding(
padding: const EdgeInsets.all(80.0),
child: Align(
alignment: Alignment.topCenter,
child: Neumorphic(
boxShape: NeumorphicBoxShape.circle(),
padding: EdgeInsets.all(10),
style: NeumorphicStyle(
depth: NeumorphicTheme.embossDepth(context),
),
child: CustomPaint(
painter: NeuProgressPainter(
circleWidth: 20,
completedPercentage: percentage,
defaultCircleColor: Colors.transparent,
),
child: Center(),
),
),
),
);
}
Widget pedometerInnerDial(context) {
return Align(
child: Neumorphic(
boxShape: NeumorphicBoxShape.circle(),
padding: EdgeInsets.all(80),
style: NeumorphicStyle(
color: Colors.white,
depth: NeumorphicTheme.depth(context),
),
),
);
}
Also I haven't used Media Query here for any of the dials, so will that be an issue for displaying on other devices?
Since you are using a stack widget, the best way to do this is to use a positioned widget. You can place the widget on top by wrapping it with Positioned and setting the top property to 0.
Here is an example:
Positioned(
top:0,
child:YourWidget(),
),
Alignment won't work for the stack widget because it only aligns the items when there are extra space around it. Example: It works in a Column or Row since they occupy space and allow the widgets inside it to be placed and move around the occupied space.

Color of a widget inside a Stack is always slightly transparent

I display a custom-made bottom app bar in a Stack because of keyboard padding reasons. The custom widget is fully opaque as it should be until it's a child of a Stack in which case, the content behind it starts to be visible since the color's opacity somehow changes.
As you can see, it's only the "main" color that's transparent. Icons remain opaque.
This is the build method of my custom BottomBar widget which is then just regularly put into a Stack. I have tried using a Material and even a simple Container in place of the BottomAppBar widget but the results are the same.
#override
Widget build(BuildContext context) {
return BottomAppBar(
color: Colors.blue.withOpacity(1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(MdiIcons.plusBoxOutline),
onPressed: () {},
),
Text('Edited 11:57'),
IconButton(
icon: Icon(MdiIcons.dotsVertical),
onPressed: () {},
),
],
),
);
}
Can you interact with the BottomAppBar ? It looks like an order problem. Try to put the BottomAppBar as last in the Stack children.
Note that BottomAppBar doesn't have a constant size, if you did not add it to Scaffold bottomNavigationBar named parameter has a size if this is not null. Below is peace of code in Scaffold dart file:
double bottomNavigationBarTop;
if (hasChild(_ScaffoldSlot.bottomNavigationBar)) {
final double bottomNavigationBarHeight = layoutChild(_ScaffoldSlot.bottomNavigationBar, fullWidthConstraints).height;
bottomWidgetsHeight += bottomNavigationBarHeight;
bottomNavigationBarTop = math.max(0.0, bottom - bottomWidgetsHeight);
positionChild(_ScaffoldSlot.bottomNavigationBar, Offset(0.0, bottomNavigationBarTop));
}
You can even develop your own Widget without BottomAppBar but if you want things like centerDocked and things like circular notched, you will have to do more stuff (anyway you have flexibility to custom design the way you want).
Here is a simple example to do that(one way to do that):
import 'package:flutter/material.dart';
class CustomBottomBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 50),
color: Colors.greenAccent, // if you want this color under bottom bar add the margin to list view
child: ListView.builder(
itemCount: 100,
itemBuilder: (_, int index) => Text("Text $index"),
),
),
Positioned(
bottom: 0,
child: Container(
color: Colors.amber.withOpacity(.5),
width: MediaQuery.of(context).size.width,
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(4, (int index) => Text("Text $index")), // you can make these clickable by wrapping with InkWell or any gesture widget
),
),
),
],
),
);
}
}