Flutter PageView dynamic height - flutter

I created a PageView with a fixed value but it is an issue. How i am gonna convert this to dynamic height? SizedBox is in a Column's child. I tried Expanded and Flexible widgets but they did not work.
class BranchViewBottomSection extends ConsumerWidget {
const BranchViewBottomSection({
Key? key,
required this.data,
required this.branchId,
required this.companyId,
}) : super(key: key);
final Map<String, dynamic> data;
final String branchId;
final String companyId;
#override
Widget build(BuildContext context, WidgetRef ref) {
return Column(
children: [
SizedBox(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: data['available_sections'].length,
itemBuilder: (BuildContext context, int index) {
if (data['available_sections'][index]["branchTabValue"] ==
ref.read(tabIndexProvider)) {
return BranchSectionBox(
data: data, index: index, isActive: true);
} else {
return BranchSectionBox(
data: data, index: index, isActive: false);
}
},
),
],
),
),
GestureDetector(
onTap: () {
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
MenuView(
branchId: branchId,
companyId: companyId,
branchData: data,
),
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
final tween = Tween(begin: begin, end: end);
final curvedAnimation = CurvedAnimation(
parent: animation,
curve: curve,
);
return SlideTransition(
position: tween.animate(curvedAnimation),
child: child,
);
},
),
);
},
child: Container(
height: 50,
width: MediaQuery.of(context).size.width,
color: Colors.pink,
child: const Center(
child: Text(
"Sipariş vermek için dokunun.",
style: TextStyle(color: Colors.white),
),
),
),
),
Expanded(
child: PageView(
onPageChanged: (v) {
ref.watch(tabIndexProvider.notifier).state =
data['available_sections'][v]['branchTabValue'];
},
children: <Widget>[
BranchViewHomePage(),
BranchViewDetailsPage(),
const BranchViewCommentsPage(),
BranchViewContactPage(),
],
),
)
],
);
}
}
This is the parent.
// ignore_for_file: non_constant_identifier_names, file_names
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:neshapp/comps/common/MainCircularProgressIndicator.dart';
import 'package:neshapp/services/FirestoreService.dart';
import 'package:neshapp/utils/constants.dart';
import '../../providers/BranchViewProviders.dart';
import '../../providers/MenuProviders.dart';
import 'BranchSectionBoxes.dart';
class BranchView extends ConsumerWidget {
final String branchId;
final String companyId;
final String tableNo;
const BranchView(
{Key? key,
required this.branchId,
required this.companyId,
required this.tableNo})
: super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
/*
Uygulamanın her yerinde kullanabilmek için eğer bir şubeye
girilirse şubenin ve markanın id'lerini providerlara veriyorum.
*/
ref.watch(branchIdProvider.notifier).setId(branchId);
ref.watch(companyIdProvider.notifier).setId(companyId);
ref.watch(tableNoProvider.notifier).setTable(tableNo);
return SafeArea(
child: Scaffold(
body: FutureBuilder<DocumentSnapshot>(
future: FirestoreService.getBranchData(companyId, branchId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final data = snapshot.data?.data() as Map<String, dynamic>;
return CustomScrollView(
scrollBehavior: const ScrollBehavior(),
slivers: <Widget>[
SliverAppBar(
elevation: 0,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("${data['branch_name']} Şubesi"),
FutureBuilder<DocumentSnapshot>(
future: FirestoreService.getCompanyData(companyId),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
final CData =
snapshot.data?.data() as Map<String, dynamic>;
return Container(
height: 40,
width: 40,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: constsColor.black.withOpacity(0.5),
),
child: Image.network(CData['company_logo']),
);
} else {
return const MainCircularProgressIndicator();
}
},
),
],
),
pinned: true,
expandedHeight: 200,
backgroundColor: constsColor.neshMoru,
flexibleSpace: FlexibleSpaceBar(
background: AspectRatio(
aspectRatio: 16 / 9,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(data['branch_image']),
fit: BoxFit.cover,
),
),
),
Positioned(
bottom: 10,
right: 10,
child: Text(
tableNo,
style: TextStyle(
color: constsColor.white,
fontSize: 18,
),
),
),
],
),
),
),
),
SliverToBoxAdapter(
child: BranchViewBottomSection(
data: data,
branchId: branchId,
companyId: companyId,
),
),
],
);
} else {
return const Center(
child: MainCircularProgressIndicator(),
);
}
},
),
),
);
}
}

expand and flexible i believe are both depend on the parten widget.
how about using the state for that ?

Related

Flutter Cubit fetching and displaying data

I'm trying to fetch data from Genshin API, code below is working, but only with delay (in GenshinCubit class), it looks weard, because I don't know how much time to set for delay. I think, there is a problem in code, cause it must not set the GenshinLoaded state before the loadedList is completed. Now, if I remove the delay, it just sets the GenshinLoaded when the list is still in work and not completed, await doesn't help. Because of that I get a white screen and need to hot reload for my list to display.
class Repository {
final String characters = 'https://api.genshin.dev/characters/';
Future<List<Character>> getCharactersList() async {
List<Character> charactersList = [];
List<String> links = [];
final response = await http.get(Uri.parse(characters));```
List<dynamic> json = jsonDecode(response.body);
json.forEach((element) {
links.add('$characters$element');
});
links.forEach((element) async {
final response2 = await http.get(Uri.parse(element));
dynamic json2 = jsonDecode(response2.body);
charactersList.add(Character.fromJson(json2));
});
return charactersList;
}
}
class GenshinCubit extends Cubit<GenshinState> {
final Repository repository;
GenshinCubit(this.repository) : super(GenshinInitial(),);
getCharacters() async {
try {
emit(GenshinLoading());
List<Character> list = await repository.getCharactersList();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(GenshinLoaded(loadedList: list));
}catch (e) {
print(e);
emit(GenshinError());
}
}
}
class HomeScreen extends StatelessWidget {
final userRepository = Repository();
HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<GenshinCubit>(
create: (context) => GenshinCubit(userRepository)..getCharacters(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Container(child: const CharactersScreen())),
),
);
}
}
class CharactersScreen extends StatefulWidget {
const CharactersScreen({
Key? key,
}) : super(key: key);
#override
State<CharactersScreen> createState() => _CharactersScreenState();
}
class _CharactersScreenState extends State<CharactersScreen> {
#override
Widget build(BuildContext context) {
return Column(
children: [
BlocBuilder<GenshinCubit, GenshinState>(
builder: (context, state) {
if (state is GenshinLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
if (state is GenshinLoaded) {
return SafeArea(
top: false,
child: Column(
children: [
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: state.loadedList.length,
itemBuilder: ((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 50.0, horizontal: 50),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailsPage(
character: state.loadedList[index],
),
),
),
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(
30,
),
)),
child: Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
right: 30.0, bottom: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
state.loadedList[index].name
.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 50),
),
RatingBarIndicator(
itemPadding: EdgeInsets.zero,
rating: double.parse(
state.loadedList[index].rarity
.toString(),
),
itemCount: int.parse(
state.loadedList[index].rarity
.toString(),
),
itemBuilder: (context, index) =>
Icon(
Icons.star_rate_rounded,
color: Colors.amber,
))
],
),
),
),
),
),
);
})),
),
],
),
);
}
if (state is GenshinInitial) {
return Text('Start');
}
if (state is GenshinError) {
return Text('Error');
}
return Text('Meow');
}),
],
);
}
}
I found a solution!
I've got that problem because of forEach. How to wait for forEach to complete with asynchronous callbacks? - there is a solution.

How to fix Image overflow in Flutter PageView?

I'm building an app where it shows the title, author name, number of upvotes, and an image from the subreddit in a page view. Everything is working fine but for some images, the page view is overflowing, how do I fix this?
Here's the overflow error:
Here's my code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class Stardew extends StatefulWidget {
const Stardew({ Key? key }) : super(key: key);
#override
State<Stardew> createState() => _StardewState();
}
class _StardewState extends State<Stardew> {
List data = [];
Future<String> getData() async {
List temp_data = [];
var response = await http.get(
Uri.parse("https://m...content-available-to-author-only...p.com/gimme/stardewvalley/100")
);
return response.body;
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getData(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if(snapshot.data == null){
return Center(child: CircularProgressIndicator(color: Color(0xff008b00)));
}
var jsonData = jsonDecode(snapshot.data);
jsonData = jsonData["memes"];
return PageView.builder(
//scrollDirection: Axis.vertical,
itemCount: jsonData.length,
itemBuilder: (BuildContext context, int index){
return Center(
child: Padding(
padding: const EdgeInsets.all(1.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
getImgCard(
jsonData[index]["title"],
//jsonData[index]["preview"][2],//preview image
jsonData[index]["url"], //original image
jsonData[index]["author"],
(jsonData[index]["ups"]).toString()
)
],
),
),
);
},
);
}
);
}
Widget getImage(String imgUrl){
return Container(
child: Image.network(
imgUrl,
fit: BoxFit.scaleDown,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded/loadingProgress.expectedTotalBytes! : null,
color: Color(0xff008b00),
),
);
},
),
);
}
Widget getImgCard(String title, String imgUrl, String author, String ups){
return Card(
color: Color(0xff000000),
clipBehavior: Clip.antiAlias,
child: Column(
children: [
ListTile(
leading: RichText(
text: TextSpan(
children: [
TextSpan(
text: ups,
),
const WidgetSpan(
child: Icon(Icons.arrow_upward, size: 18, color: Color(0xff008b00),),
)
],
),
),
title: Text(title, style: TextStyle(color: Colors.white),),
subtitle: Text(
"Posted by u/${author}",
style: TextStyle(color: Colors.white.withOpacity(0.6)),
),
),
getImage(imgUrl),
Padding(padding: EdgeInsets.only(bottom: 8))
],
),
);
}
}
How do I fix this? I have tried changing the box fit and it did not work. Then I used expaned and flexible widgets and still can't find the answer to this solution. please help me.
Wrap getImage(imgUrl) inside Expanded widget.
I found the answer myself, removing the parent column and wrapping it with SingleChildScrollView fixed the error.
return PageView.builder(
//scrollDirection: Axis.vertical,
itemCount: jsonData.length,
itemBuilder: (BuildContext context, int index){
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(1.0),
child: getImgCard(
jsonData[index]["title"],
//jsonData[index]["preview"][2],//preview image
jsonData[index]["url"], //original image
jsonData[index]["author"],
(jsonData[index]["ups"]).toString()
),
)
);
},
);

Center a listview child on selection

I am trying to make all the selected dates to be yellow background and always in the center, how can I achieve that ?
What I have right now :
Here's what I have achieve so far :
Current date selected : https://i.stack.imgur.com/P2bPp.png
Another date selected : https://i.stack.imgur.com/oKFXu.png
Example of what I'm trying to achieve :
https://i.stack.imgur.com/yb6Lx.png
https://i.stack.imgur.com/G9rZc.png
Please advice. Thanks in advance.
Here is my code :
Date_picker
return Container(
height: 85.0,
margin: EdgeInsets.only(left: 20.0, right: 20.0),
child: ListView.builder(
scrollDirection: Axis.horizontal,
controller: _controller,
itemCount: daysCount,
itemBuilder: (context, index) {
int daysCountBefore = daysCount ~/ 2;
DateTime today = DateTime.now();
//get half of the days count before today first then start up total daysCount
// 2021-01-30 15:31:16.481
DateTime startDate =
today.subtract(Duration(days: daysCountBefore));
//convert to 00:00:00.000 hours
// 2021-01-30 00:00:00.000
DateTime _startDate =
new DateTime(startDate.year, startDate.month, startDate.day);
// print(_startDate.day);
// print(daysCountBefore);
//show days count from start date
DateTime dates = _startDate.add(Duration(days: index));
//format to 00:00:00.00 hrs
//mainly for _compareDates();
DateTime _dates = new DateTime(dates.year, dates.month, dates.day);
bool isSelected = _currentDate != null
? _compareDates(_dates, _currentDate)
: false;
return DateWidget(
date: dates,
width: isSelected ? 65.0 : 40.0,
selectedColor:
isSelected ? widget.selectedDateColor : Colors.transparent,
dayNumTextStyle: isSelected
? kSelectedDayNumTextStyle
: kNotSelectedDayNumTextStyle,
dayMonthTextStyle: isSelected
? kSelectedDayMonthTextStyle
: kNotSelectedDayMonthTextStyle,
dateTapped: (dateToShow) {
//change state to the date that is tapped
setState(() {
_currentDate = dateToShow;
});
//Callback
widget.onDateChange(dateToShow);
},
);
},
));
Date_widget :
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class DateWidget extends StatelessWidget {
final DateTime date;
final TextStyle textStyle;
final Color selectedColor;
final TextStyle dayMonthTextStyle;
final Function(DateTime) dateTapped;
final double width; //75.0
final TextStyle dayNumTextStyle;
DateWidget(
{#required this.date,
#required this.dateTapped,
this.textStyle,
this.width,
this.selectedColor,
this.dayNumTextStyle,
this.dayMonthTextStyle});
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
margin: EdgeInsets.all(3.0),
width: width,
height: 80.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
color: selectedColor,
),
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(new DateFormat('MMM').format(date).toUpperCase(),
style: dayMonthTextStyle),
Text(date.day.toString(), style: dayNumTextStyle),
Text(
new DateFormat('E').format(date).toUpperCase(),
// style: TextStyle(fontWeight: FontWeight.bold)
style: dayMonthTextStyle,
)
],
),
)),
onTap: () {
dateTapped(date);
});
}
}
Here is a solution based only on ListView.builder and its ScrollController:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
void main() {
runApp(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: MyWidget(data: List.generate(100, (index) => index)),
),
),
);
}
class MyWidget extends HookWidget {
final List<int> data;
const MyWidget({Key key, this.data}) : super(key: key);
#override
Widget build(BuildContext context) {
final _scrollController = useScrollController();
final _selected = useState(0);
return LayoutBuilder(
builder: (context, constraints) {
final double size = constraints.biggest.width / 10;
return SizedBox(
height: size,
child: ListView.builder(
controller: _scrollController,
scrollDirection: Axis.horizontal,
itemExtent: size,
itemCount: data.length,
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.all(size * .05),
child: GestureDetector(
onTap: () {
_selected.value = index;
_scrollController.animateTo(
max(index - 4.5, 0) * size,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);
},
child: Card(
color: _selected.value == index
? Colors.amber
: Colors.lightGreen.shade100,
child: Center(
child: Text(data[index].toString()),
),
),
),
),
),
);
},
);
}
}
You can use Carousel Slider
Example -
CarouselSlider(
options: CarouselOptions(height: 400.0),
items: [1,2,3,4,5].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(
color: Colors.amber
),
child: Text('text $i', style: TextStyle(fontSize: 16.0),)
);
},
);
}).toList(),
)

flutter check if data exists in firestore

I've been trying to check if user selected data matches with my firestore data.
onPressed: () async{
await Navigator.of(context).push(MaterialPageRoute(builder: (context) => Checker (
from: fromSel,
to: toSel,
)));
},
and in the second page i used
StreamBuilder(
stream: Firestore.instance
.collection('Schedules')
.where('from', isEqualTo: from)
.where('to', isEqualTo: to)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index){
DocumentSnapshot power = snapshot.data.documents[index];
print(power['from']);
print(power['to']);
return Container(
height: 200,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Text(power['from']),
Text(power['to'])
],
),
);
}
);
}),
so the problem i'm getting is it's not displaying the value when i use .where('from', isEqualTo: from) but it works when i use .where('from', isEqualTo: 'Adama'). and also works with .where('from', isEqualTo: from) when i instantiate from value manually like String from = 'Adama'
can you please tell me what the problem is?
and below is my firestore structure
below is the whole code for the checker (renamed to search)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:demo/BookingPages/budget.dart';
import 'package:demo/Lists/trip.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Search extends StatefulWidget {
final from, to, seat, adult, child, infant;
final DateTime arrive, depart;
Search(
{Key key, this.from, this.to, this.seat, this.arrive, this.depart, this.adult, this.infant, this.child})
: super(key: key);
#override
_SearchState createState() => _SearchState(from: from, to: to, seat: seat, adult: adult, child: child, infant: infant, arrive: arrive, depart: depart);
}
class _SearchState extends State<Search> {
// Stream<QuerySnapshot> comparision;
var from, to, seat, adult, child, infant;
final DateTime arrive, depart;
_SearchState(
{Key key, this.from, this.to, this.seat, this.arrive, this.depart, this.adult, this.infant, this.child});
Stream<QuerySnapshot> comparision(BuildContext context) async* {
try{
yield* Firestore.instance
.collection('Schedules')
.where('from', isEqualTo: from.toString())
.where('to', isEqualTo: to.toString())
// .where('dates', arrayContains: widget.depart.day)
.snapshots();
}catch(e){
print(e);
}
}
// #override
// void initState() {
// // TODO: implement initState
// comparision = Firestore.instance
// .collection('Schedules')
// .where('from', isEqualTo: from)
// .where('to', isEqualTo: to)
// .snapshots();
//
// super.initState();
// }
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: StreamBuilder(
stream: Firestore.instance
.collection('Schedules')
.where('from', isEqualTo: from)
.where('to', isEqualTo: to)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index){
DocumentSnapshot power = snapshot.data.documents[index];
print(power['from']);
print(power['to']);
return Container(
height: 200,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Text(power['from']),
Text(power['to'])
],
),
);
}
);
}),
)
// Expanded(
// child: StreamBuilder<QuerySnapshot>(
// stream: comparision,
// builder: (BuildContext context, AsyncSnapshot<QuerySnapshot>snapshot) {
// if (!snapshot.hasData)
// return Center(child: CircularProgressIndicator());
// return ListView.builder(
// itemCount: snapshot.data.documents.length,
// itemBuilder: (context, index){
// DocumentSnapshot power = snapshot.data.documents[index];
// print(power['from']);
// print(power['to']);
// return Container(
// height: 200,
// width: MediaQuery.of(context).size.width,
// child: Column(
// children: [
// Text(power['from']),
// Text(power['to'])
// ],
// ),
// );
// }
// );
// },
// ),
// ),
],
)
);
}
}
class TripCard extends StatefulWidget {
#override
_TripCardState createState() => _TripCardState();
}
class _TripCardState extends State<TripCard> {
#override
Widget build(BuildContext context) {
return Container();
}
}
below is my first page code which includes the values
import 'package:flutter/material.dart';
import 'search.dart';
class Other extends StatefulWidget {
#override
_OtherState createState() => _OtherState();
}
class _OtherState extends State<Other> {
var from = [
'Addis Ababa', 'Adama', 'Dire Dawa', 'Ali Sabieh', 'Djibouti'
];
var fromSel = 'Addis Ababa';
var to = [
'Addis Ababa', 'Adama', 'Dire Dawa', 'Ali Sabieh', 'Djibouti'
];
var toSel = 'Djibouti';
#override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Container(
//height: 203,
child: Column(
children: [
SizedBox(height: 15,),
Container(
//decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: MediaQuery.of(context).size.width/2-19,
height: 60,
padding: EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('From', style: TextStyle(
fontSize: 18,
color: Colors.grey
),),
SizedBox(height: 0,),
Expanded(
child: DropdownButton<String>(
underline: Container(color: Colors.transparent),
items: from.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value, style: TextStyle(
fontSize: 18
),),
);
}).toList(),
isExpanded: true,
isDense: false,
elevation: 5,
hint: Text('From'),
value: fromSel,
onChanged: (String newValue){
setState(() {
this.fromSel = newValue;
});
}),
),
],
),
),
Container(height: 50, child: VerticalDivider(color: Colors.grey)),
Container(
width: MediaQuery.of(context).size.width/2-19,
height: 60,
padding: EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('To', style: TextStyle(
fontSize: 18,
color: Colors.grey
),),
SizedBox(height: 0,),
Expanded(
child: DropdownButton<String>(
underline: Container(color: Colors.transparent),
items: to.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value, style: TextStyle(
fontSize: 18
),),
);
}).toList(),
isExpanded: true,
isDense: false,
elevation: 5,
hint: Text('to'),
value: toSel,
onChanged: (String newValue){
setState(() {
this.toSel = newValue;
});
}),
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
child: MaterialButton(
onPressed: () async{
await Navigator.of(context).push(MaterialPageRoute(builder: (context) => Search (
from: fromSel,
to: toSel,
depart: _startDate,
arrive: _endDate,
seat: _options[_selectedIndex],
adult: adultSel.toString(),
child: childSel.toString(),
infant: infantSel.toString(),
)));
},
minWidth: MediaQuery
.of(context)
.size
.width - 80,
height: 45,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
color: Colors.lightGreen,
splashColor: Colors.green,
child: Text(
"Search",
style: TextStyle(color: Colors.white, fontSize: 18),
),
),
)
],
),
),
),
);
}
}

Adjust Z-Index in flutter

I try to place an element above another element in flutter. With transform: Matrix4.translationValues it worked to set a negative value, but the element above has a bigger z-index. How could I adjust that? To understand what I need:
This is what I have
This is what I need
My code
class _AlbumDetailState extends State<AlbumDetail> {
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, int>;
final albumID = routeArgs['id'];
final index = routeArgs['index'];
final picturesData = Provider.of<Pictures>(context, listen: true);
Future<void> _addPictureToGallery() async {
final picker = ImagePicker();
final imageFile =
await picker.getImage(source: ImageSource.gallery, maxWidth: 600);
final appDir = await syspath.getApplicationDocumentsDirectory();
final fileName = path.basename(imageFile.path);
final savedImage =
await File(imageFile.path).copy('${appDir.path}/$fileName');
print(savedImage);
picturesData.add(Picture(
album: albumID, path: savedImage.path, timestamp: Timestamp.now()));
}
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text("Album"),
flexibleSpace: FlexibleSpaceBar(
background: Container(
color: Colors.transparent,
child: Hero(
tag: "open_gallery" + index.toString(),
child: Image(
image: NetworkImage('https://placeimg.com/640/480/any'),
fit: BoxFit.cover,
),
),
)),
expandedHeight: 350,
backgroundColor: Colors.green,
pinned: true,
stretch: false,
),
SliverToBoxAdapter(
child: FutureBuilder(
future: picturesData.getPicturesFromAlbum(albumID),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data.length == 0) {
return Center(
child: Text("Noch keine Bilder vorhanden"),
);
}
if (!snapshot.hasData ||
snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.center,
transform: Matrix4.translationValues(0.0, -75.0, 0.0),
width: MediaQuery.of(context).size.width - 50,
height: 150,
color: Colors.black87,
margin: EdgeInsets.only(top: 50),
child: Text(
"Headline",
style: Theme.of(context)
.textTheme
.headline2
.copyWith(color: theme.colorScheme.onPrimary),
),
),
StaggeredGridView.countBuilder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 6,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) =>
Container(
child: Image.file(
File(snapshot.data[index].path),
fit: BoxFit.cover,
)),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 1),
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
),
],
);
}
}),
)
],
),
);
}
}
The problem: The z-index is not correct on my element. My header is above. How could I adjust the z-index? I know this from CSS. Is there a way to to this with flutter?
One way of achieving overlapping widgets is by using Stack widget. You can check the docs for more details.
try this package https://pub.dev/packages/indexed
https://raw.githubusercontent.com/physia/kflutter/main/indexed/doc/assets/demo.gif
This package allows you to order items inside stack using index like z-index in css
this is example how it works
Indexer(
children: [
Indexed(
index: 100,
child: Positioned(
//...
)
),
Indexed(
index: 1000,
child: Positioned(
//...
)
),
Indexed(
index: 3,
child: Positioned(
//...
)
),
],
);
if you are using bloc of some complex widget you can extands or implement the IndexedInterface class and override index getter:
class IndexedDemo extends IndexedInterface {
int index = 5;
}
or implements
class IndexedDemo extends AnimatedWidget implements IndexedInterface {
int index = 1000;
//...
//...
}
then use it just like Indexed class widget:
Indexer(
children: [
IndexedDemo(
index: 100,
child: Positioned(
//...
)
),
IndexedFoo(
index: 1000,
child: Positioned(
//...
)
),
],
);
Online demo
Video demo