How to remove space after Transform.translate in CustomScrollView? - flutter

Help me, any idea how to remove the space between yellow and green Container?
It's caused by the Container have additional height after transform translate.
I need CustomSrollView with SliverAppBar and a child below it.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: Scaffold(
body: Example(),
),
);
}
}
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CustomScrollView(slivers: [
SliverSafeArea(
top: false,
sliver: SliverAppBar(
backgroundColor: Colors.black.withOpacity(0.2),
floating: true,
toolbarHeight: 0,
bottom: const PreferredSize(
preferredSize: Size.fromHeight(30), child: Text("AppBar")),
),
),
SliverToBoxAdapter(
child: Transform.translate(
offset: const Offset(0.0, -30.0),
child: Container(height: 500, color: Colors.yellow),
),
),
SliverToBoxAdapter(
child: Align(child: Container(height: 500, color: Colors.green))),
]);
}
}

Ok, you want to move the yellow container, but you don't want to take translate spaces the space. I don't know what design you are doing, I may just reduce the height in this case. Or use padding in extra spaces.
According to the question, we can use stack like.
SliverToBoxAdapter(
child: Container(
color: Colors.amber,
height: 500 + 500,
child: Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 500,
color: Colors.green,
),
),
Positioned(
bottom: 500 - 30,
child: Transform.translate(
offset: const Offset(0.0, -30.0),
child: Container(
height: 500,
color: Colors.yellow,
),
),
),
],
),
),
),
But in this case we are overlapping with green container.
We can
reduce the size,
use stack, will overlap with green container

Related

Flutter: Getting relative height of widget for vericalDivider

Im building a screen where a widget is supposed to look like a Tweet. Im trying to implement the vertical bars seen under profile pictures with the following:
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
VerticalDivider(
color: Colors.red,
thickness: 10,
width: 20,
),
//make a widget that looks like twitter composing tweet
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage(user.imageUrls[0]),
),
//add a gray line that runs down the middle of the screen
VerticalDivider(
color: Colors.red,
thickness: 10,
width: 200,
),
],
),
),
Which looks like this:
As you can see, the dividers are invisible. Wrapping the divider with a specified height makes it look like this:
It is now visible, but obviously expands outside of the original size of the widget. Is there any way to pass the size of the parent into the VerticalDivider so i knows how much space it has to work with?
Thanks!
You can wrap your Row with the IntrinsicHeight widget. It will set the rows height based on its tallest child (here the Container with height = 200). Of course in your example you don't know the tallest child's size before layout, I used the container simply to give you an example. IntrinsicHeight is relatively expensive to use but the right choice for such use cases (see its docs).
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 StatelessWidget {
#override
Widget build(BuildContext context) {
return IntrinsicHeight(
child: Row(
children: [
Container(
color: Colors.grey,
child: Column(
children: [
SizedBox(
child: VerticalDivider(
color: Colors.red,
thickness: 10,
width: 20,
),
height: 20,
),
Container(height: 40, width: 40, color: Colors.blue),
Expanded(
child: VerticalDivider(
color: Colors.red,
thickness: 10,
width: 20,
),
),
],
),
),
Container(
height: 200,
width: 200,
color: Colors.white,
)
],
),
);
}
}

not overlap SliverToBoxAdapter with a transparent SliverAppBar

Is it possible for a SliverToBoxAdapter to not be overlaped with a transparentSliverAppBar when scrolled upon?
Or give up on using SliverAppBar and just use AppBar instead?
Widget build(BuildContext context) {
return SafeArea(
child: Stack(
children: [
Image(
image: bkgImage,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
alignment: Alignment.centerLeft,
),
Scaffold(
backgroundColor: Colors.transparent,
body: CustomScrollView(
slivers: [
SliverAppBar(
actions: <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: () {},
),
],
pinned: _pinned,
snap: _snap,
floating: _floating,
expandedHeight: 160,
backgroundColor: Colors.transparent,
elevation: 0.0,
flexibleSpace: FlexibleSpaceBar(
expandedTitleScale: 1.6,
titlePadding: EdgeInsets.all(18),
title: Text('Panahon'),
),
),
SliverList(
delegate: SliverChildListDelegate([
SizedBox(
height: 200,
child: Card(),
),
SizedBox(
height: 200,
child: Card(),
),
SizedBox(
height: 200,
child: Card(),
),
SizedBox(
height: 200,
child: Card(),
),
SizedBox(
height: 200,
child: Card(),
),
]),
)
],
),
),
],
),
);
}
The goal is this:
Precious view:
To get actual effect, we can use SliverPersistentHeaderDelegate. Concept is we need to pass image itself [both image must be screen size].
class MySliverHeaderDelegate extends SliverPersistentHeaderDelegate {
final double _maxExtent = 160;
final VoidCallback onActionTap;
final Image imageWidget;
MySliverHeaderDelegate({
required this.onActionTap,
required this.imageWidget,
});
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
debugPrint(shrinkOffset.toString());
return Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: imageWidget,
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(
'Panahon',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Colors.white,
),
),
),
),
// here provide actions
Positioned(
top: 0,
right: 0,
child: IconButton(
icon: const Icon(
Icons.search,
color: Colors.white,
),
onPressed: onActionTap,
),
),
],
);
}
#override
double get maxExtent => _maxExtent;
#override
double get minExtent => kToolbarHeight;
#override
bool shouldRebuild(covariant MySliverHeaderDelegate oldDelegate) {
return oldDelegate != this;
}
}
And use
Widget build(BuildContext context) {
final imageWidget = Image.asset(
"assets/images/image01.png",
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
alignment: Alignment.centerLeft,
);
return SafeArea(
child: Stack(
children: [
imageWidget,
Scaffold(
backgroundColor: Colors.transparent,
body: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: MySliverHeaderDelegate(
imageWidget: imageWidget,
onActionTap: () {
debugPrint("on Tap");
}),
),
//.....
],
),
),
],
),
);
}
Others way to handle this situation
Being SliverAppBar's backgroundColor:Colors.transparent you are able to see though appbar.
If you provide your preferable color, that will fix the issue in this case, but you will not get background effect on appBar.
SliverAppBar(
backgroundColor: Colors.green, // the one you like
For your case, you can use CupertinoSliverNavigationBar instead of using SliverAppBar. It will still block the background on scroll and it won't get that much height.
CupertinoSliverNavigationBar(
backgroundColor: Colors.transparent,
largeTitle: const Align(
alignment: Alignment.bottomLeft,
child: SizedBox(
child: Text('Panahon'),
),
),
trailing: IconButton(
icon: const Icon(Icons.search),
onPressed: () {},
),
),

Content of a SingleChildScrollView get undrawn when keyboard is open before the keyboard is completely open

I noticed that having some content inside a SingleChildScroll view and having also a TextField inside it. If i start typing causing the keyboard to open the content under the keyboard get undrawn before the keyboard is completely open. Is that a flutter's bug or am i doing something wrong?
From this video you can see that the content under the keyboard becomes white before it ended open
There is my code
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SingleChildScrollView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(),
Container(
height: 200,
color: Colors.red,
),
Container(
height: 200,
color: Colors.purple,
),
Container(
height: 200,
color: Colors.yellow,
),
Container(
height: 200,
color: Colors.green,
),
Container(
height: 200,
color: Colors.blue,
),
],
),
),
),
);
}
}
This happens because Scaffold(); is supposed to draw every widget above keyboard by default.
But adding the property resizeToAvoidBottomInset: false, to Scaffold(); override the default behaviour and hence return the result you're looking for.
Heres the full code
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SingleChildScrollView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(),
Container(
height: 200,
color: Colors.red,
),
Container(
height: 200,
color: Colors.purple,
),
Container(
height: 200,
color: Colors.yellow,
),
Container(
height: 200,
color: Colors.green,
),
Container(
height: 200,
color: Colors.blue,
),
],
),
),
),
);
}
}

Flutter OverflowBox is behind the next widget in a column

I'm working on a Flutter project and I am trying to use the OverflowBox widget.
I have a list of widgets in a Column, one of them, in the middle is supposed to overflow the others based on some events by the user.
Here is a simplified version of my code.
The red Container needs to display the green Container that overflows it at the top and the bottom.
But as you can see on the image, the green Container is only visible above the previous Container (the blue one) but not on the next one (the black Container). It looks like it is behind.
class MyScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 100,
width: 100,
color: Colors.blue,
),
Container(
height: 100,
width: 100,
color: Colors.red,
child: Center(
child: OverflowBox(
maxHeight: 150,
child: Container(
color: Colors.green,
height: 150,
width: 50,
),
),
),
),
Container(
height: 100,
width: 100,
color: Colors.black,
)
],
);
}
}
How can I get my green Container to be above the black one too ?
EDIT: For functionality purposes, I need the green Container to be a child/be created by the red Container (and not by the list where I could use a Stack widget). I need the logic to be inside the red and green ones.
It still uses Stack, but Green Container is still part of Red Container.
And it might be difficult to calculate margin if Container has dynamic height.
class MyScreen extends StatelessWidget {
const MyScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
height: 100,
width: 100,
color: Colors.blue,
),
Container(
margin: const EdgeInsets.only(top: 200),
height: 100,
width: 100,
color: Colors.black,
),
Container(
margin: const EdgeInsets.only(top: 100),
height: 100,
width: 100,
color: Colors.red,
child: Center(
child: OverflowBox(
maxHeight: 150,
child: Container(
height: 150,
width: 50,
color: Colors.green,
),
),
),
),
],
),
);
}
}
Use of overlay, maybe solve your problem.
OverlayState? overlayState = Overlay.of(context);
I tried your code snipped and failed to getting the design that you particularly wishing to achieve.
I have anther way to get such type of design. Which ia using Stacl() widget
Here is an complete example code snippet
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: Center(
child: MyScreen(),
),
),
);
}
}
class MyScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: MediaQuery.of(context).size.height/3,
width: MediaQuery.of(context).size.width,
color: Colors.blue,
),
Container(
height: MediaQuery.of(context).size.height/3,
width: MediaQuery.of(context).size.width,
color: Colors.red,
),
Container(
height: MediaQuery.of(context).size.height/3,
width: MediaQuery.of(context).size.width,
color: Colors.black,
)
],
),
Positioned(
// to set a specific position of your widget use Positioned inside a Stack() widget
/*
bottom: 50,
top: MediaQuery.of(context).size.height/3,
left: 100,
right: 100,
*/
child: OverflowBox(
child: Container(
color: Colors.green,
height: MediaQuery.of(context).size.height/2,
width: 100,
),
),
),
],
);
}
}
Output:

Flutter Stack widget not sizing correctly when used in a ListView

I'm trying to build a List of Card's that contain a Stack widget, the Card + Stack Widget works just fine until I make it the child of a list view, and then the Stack no longer sizes automatically to its largest child. This is causing my view that should be aligned to the bottom right to only be right aligned instead since the bottom of the Stack isn't sized correctly.
I've tried wrapping all the children of the Stack with an Align, but that didn't help either. Positioned has the same results as Align.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Stack Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) => Scaffold(
body: ListView(
children: <Widget>[
_buildCard(context),
_buildCard(context),
_buildCard(context),
_buildCard(context),
_buildCard(context),
_buildCard(context),
],
),
);
Widget _buildCard(BuildContext context) => Card(
child: Stack(
children: <Widget>[
SizedBox(
height: 200,
child: Container(
color: Colors.black,
),
),
Align(
alignment: Alignment.bottomRight,
child: SizedBox(
height: 50,
width: 50,
child: Container(
color: Colors.red,
),
),
),
],
),
);
}
What I'd expect to happen, is the Stack would size correctly around the black container allowing the red container to be positioned at the bottom right of the card.
try to set the alignment on the stack too
alignment: AlignmentDirectional.bottomEnd,
like this one
Widget _buildCard(BuildContext context) => Card(
child: Stack(
alignment: AlignmentDirectional.bottomEnd,
children: <Widget>[
SizedBox(
height: 200,
child: Container(
color: Colors.black,
),
),
Align(
alignment: Alignment.bottomRight,
child: SizedBox(
height: 50,
width: 50,
child: Container(
color: Colors.red,
),
),
),
],
),
);
screenshot