Anonymous
Мне нужно нажать кнопку за пределами ModalBottomSheet, не закрывая нижний лист во Flutter.
Сообщение
Anonymous » 25 июн 2024, 14:55
Это функция для ModalBottomSheet:
Код: Выделить всё
import ...
void ridePopUp(BuildContext context, WidgetRef ref, Widget content, VoidCallback? onDone, bool actionVisible) {
showModalBottomSheet(
useRootNavigator: true,
useSafeArea: true,
enableDrag: false,
clipBehavior: Clip.antiAlias,
isScrollControlled: true,
isDismissible: false,
backgroundColor: Colors.transparent,
barrierColor: Colors.transparent,
context: context,
builder: (context) {
return RideBottomPopupSheet(
content: content,
onDone: onDone,
actionVisible: actionVisible,
);
},
);
}
class RideBottomPopupSheet extends ConsumerStatefulWidget {
const RideBottomPopupSheet({
super.key,
required this.content,
required this.actionVisible,
this.onDone,
});
final Widget content;
final VoidCallback? onDone;
final bool actionVisible;
@override
ConsumerState createState() => _RideBottomPopupSheetState();
}
class _RideBottomPopupSheetState extends ConsumerState {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(10.0)
.copyWith(bottom: MediaQuery.of(context).viewInsets.bottom + 40),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(20),
),
color: Colors.white,
),
child: Column(
children: [
Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(20),
),
color: Colors.white,
),
width: double.maxFinite,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: widget.content,
),
),
if (widget.actionVisible) ...[
CustomContainer(
borderRadius: 0,
width: double.maxFinite,
child: TextButton(
style: TextButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Constants.primaryColor,
),
clipBehavior: Clip.hardEdge,
onPressed: widget.onDone,
child: Text(
'Continue',
overflow: TextOverflow.fade,
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
),
),
],
],
),
),
),
);
}
}
Это экран, на котором вверху расположены две кнопки и отображение карты Google.
Код: Выделить всё
class BookRideScreen extends ConsumerStatefulWidget {
const BookRideScreen({super.key});
@override
ConsumerState createState() => _BookRideScreenState();
}
class _BookRideScreenState extends ConsumerState {
StateProvider terminalSelected = StateProvider((ref) => 1);
@override
void initState() {
// TODO: implement initState
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
WidgetsBinding.instance.addPostFrameCallback((_) {
ridePopUp(
context,
ref,
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
/// FIRST CHOICE --> TERMINAL 1
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: InkWell(
onTap: () {
ref.read(terminalSelected.notifier).update((state) => 1);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Consumer(builder: (context, ref, child) {
return Checkbox(
value: ref.watch(terminalSelected) == 1 ? true : false,
materialTapTargetSize: MaterialTapTargetSize.padded,
activeColor: Constants.primaryColor,
shape: const CircleBorder(),
side: const BorderSide(
width: 2,
style: BorderStyle.solid,
color: Color(0xffd9d9d9),
),
onChanged: (bool? value) {
if (value == true) {
ref
.read(terminalSelected.notifier)
.update((state) => 1);
}
},
);
}),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'Terminal 1',
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color(0xff344054),
),
),
subtitle: Text(
'Pick Up Point',
style: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: const Color(0xff344054),
),
),
),
),
],
),
),
),
const Divider(
color: Color(0xffd0d5dd),
thickness: 1.8,
),
/// Second Choice --> TERMINAL 2
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: InkWell(
onTap: () {
ref.read(terminalSelected.notifier).update((state) => 2);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Consumer(builder: (context, ref, child) {
return Checkbox(
value: ref.watch(terminalSelected) == 2 ? true : false,
materialTapTargetSize: MaterialTapTargetSize.padded,
activeColor: Constants.primaryColor,
shape: const CircleBorder(),
side: const BorderSide(
width: 2,
style: BorderStyle.solid,
color: Color(0xffd9d9d9),
),
onChanged: (bool? value) {
if (value == true) {
ref
.read(terminalSelected.notifier)
.update((state) => 2);
}
},
);
}),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'Terminal 2',
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color(0xff344054),
),
),
subtitle: Text(
'Pick Up Point',
style: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: const Color(0xff344054),
),
),
),
),
],
),
),
),
const Divider(
color: Color(0xffd0d5dd),
thickness: 1.8,
),
/// THIRD CHOICE --> TERMINAL 3
Padding(
padding: const EdgeInsets.only(left: 18.0),
child: InkWell(
onTap: () {
ref.read(terminalSelected.notifier).update((state) => 3);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Consumer(builder: (context, ref, child) {
return Checkbox(
value: ref.watch(terminalSelected) == 3 ? true : false,
materialTapTargetSize: MaterialTapTargetSize.padded,
activeColor: Constants.primaryColor,
shape: const CircleBorder(),
side: const BorderSide(
width: 2,
style: BorderStyle.solid,
color: Color(0xffd9d9d9),
),
onChanged: (bool? value) {
if (value == true) {
ref
.read(terminalSelected.notifier)
.update((state) => 3);
}
},
);
}),
Expanded(
child: ListTile(
contentPadding: EdgeInsets.zero,
title: Text(
'Terminal 3',
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color(0xff344054),
),
),
subtitle: Text(
'Pick Up Point',
style: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.w500,
color: const Color(0xff344054),
),
),
),
),
],
),
),
),
],
),
() {},
true,
);
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values); // to re-show bars
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
const GoogleMap(
initialCameraPosition: CameraPosition(
target: GoogleMapsConstants.terminal1Location,
zoom: 18,
),
),
Positioned(
top: MediaQuery.of(context).viewPadding.top,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () {},
clipBehavior: Clip.antiAlias,
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
foregroundColor: const Color(0xff344054),
backgroundColor: Colors.white,
shape: const CircleBorder(),
),
child: SvgPicture.asset('assets/svgs/uyufjdx.svg'),
),
const SizedBox(
width: 5,
),
ElevatedButton(
onPressed: () {},
clipBehavior: Clip.antiAlias,
style: ElevatedButton.styleFrom(
foregroundColor: const Color(0xff344054),
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
),
child: SvgPicture.asset('assets/svgs/gutdw.svg'),
),
],
),
),
],
),
);
}
}
Мне нужно нажать эти кнопки и взаимодействовать с GoogleMaps при открытом ModalBottomSheet. Поскольку мне нужно открыть ModalBottomSheet, как только откроется экран, нет возможности вручную открыть лист с помощью любой кнопки, он должен открываться автоматически при открытии этого экрана, и я должен иметь возможность взаимодействовать с фоном содержимое экрана.
ИЗОБРАЖЕНИЕ: Дизайн, который мне нужно реализовать:
[img]https:// i.sstatic.net/kFIXZ.jpg[/img]
Подробнее здесь:
https://stackoverflow.com/questions/774 ... ng-the-bot
1719316558
Anonymous
Это функция для ModalBottomSheet: [code]import ... void ridePopUp(BuildContext context, WidgetRef ref, Widget content, VoidCallback? onDone, bool actionVisible) { showModalBottomSheet( useRootNavigator: true, useSafeArea: true, enableDrag: false, clipBehavior: Clip.antiAlias, isScrollControlled: true, isDismissible: false, backgroundColor: Colors.transparent, barrierColor: Colors.transparent, context: context, builder: (context) { return RideBottomPopupSheet( content: content, onDone: onDone, actionVisible: actionVisible, ); }, ); } class RideBottomPopupSheet extends ConsumerStatefulWidget { const RideBottomPopupSheet({ super.key, required this.content, required this.actionVisible, this.onDone, }); final Widget content; final VoidCallback? onDone; final bool actionVisible; @override ConsumerState createState() => _RideBottomPopupSheetState(); } class _RideBottomPopupSheetState extends ConsumerState { @override Widget build(BuildContext context) { return SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(10.0) .copyWith(bottom: MediaQuery.of(context).viewInsets.bottom + 40), child: Container( clipBehavior: Clip.antiAlias, decoration: const BoxDecoration( borderRadius: BorderRadius.all( Radius.circular(20), ), color: Colors.white, ), child: Column( children: [ Container( decoration: const BoxDecoration( borderRadius: BorderRadius.all( Radius.circular(20), ), color: Colors.white, ), width: double.maxFinite, child: Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: widget.content, ), ), if (widget.actionVisible) ...[ CustomContainer( borderRadius: 0, width: double.maxFinite, child: TextButton( style: TextButton.styleFrom( foregroundColor: Colors.white, backgroundColor: Constants.primaryColor, ), clipBehavior: Clip.hardEdge, onPressed: widget.onDone, child: Text( 'Continue', overflow: TextOverflow.fade, style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w500, ), ), ), ), ], ], ), ), ), ); } } [/code] Это экран, на котором вверху расположены две кнопки и отображение карты Google. [code] class BookRideScreen extends ConsumerStatefulWidget { const BookRideScreen({super.key}); @override ConsumerState createState() => _BookRideScreenState(); } class _BookRideScreenState extends ConsumerState { StateProvider terminalSelected = StateProvider((ref) => 1); @override void initState() { // TODO: implement initState super.initState(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); WidgetsBinding.instance.addPostFrameCallback((_) { ridePopUp( context, ref, Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ /// FIRST CHOICE --> TERMINAL 1 Padding( padding: const EdgeInsets.only(left: 18.0), child: InkWell( onTap: () { ref.read(terminalSelected.notifier).update((state) => 1); }, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Consumer(builder: (context, ref, child) { return Checkbox( value: ref.watch(terminalSelected) == 1 ? true : false, materialTapTargetSize: MaterialTapTargetSize.padded, activeColor: Constants.primaryColor, shape: const CircleBorder(), side: const BorderSide( width: 2, style: BorderStyle.solid, color: Color(0xffd9d9d9), ), onChanged: (bool? value) { if (value == true) { ref .read(terminalSelected.notifier) .update((state) => 1); } }, ); }), Expanded( child: ListTile( contentPadding: EdgeInsets.zero, title: Text( 'Terminal 1', style: GoogleFonts.inter( fontSize: 18, fontWeight: FontWeight.w500, color: const Color(0xff344054), ), ), subtitle: Text( 'Pick Up Point', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w500, color: const Color(0xff344054), ), ), ), ), ], ), ), ), const Divider( color: Color(0xffd0d5dd), thickness: 1.8, ), /// Second Choice --> TERMINAL 2 Padding( padding: const EdgeInsets.only(left: 18.0), child: InkWell( onTap: () { ref.read(terminalSelected.notifier).update((state) => 2); }, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Consumer(builder: (context, ref, child) { return Checkbox( value: ref.watch(terminalSelected) == 2 ? true : false, materialTapTargetSize: MaterialTapTargetSize.padded, activeColor: Constants.primaryColor, shape: const CircleBorder(), side: const BorderSide( width: 2, style: BorderStyle.solid, color: Color(0xffd9d9d9), ), onChanged: (bool? value) { if (value == true) { ref .read(terminalSelected.notifier) .update((state) => 2); } }, ); }), Expanded( child: ListTile( contentPadding: EdgeInsets.zero, title: Text( 'Terminal 2', style: GoogleFonts.inter( fontSize: 18, fontWeight: FontWeight.w500, color: const Color(0xff344054), ), ), subtitle: Text( 'Pick Up Point', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w500, color: const Color(0xff344054), ), ), ), ), ], ), ), ), const Divider( color: Color(0xffd0d5dd), thickness: 1.8, ), /// THIRD CHOICE --> TERMINAL 3 Padding( padding: const EdgeInsets.only(left: 18.0), child: InkWell( onTap: () { ref.read(terminalSelected.notifier).update((state) => 3); }, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Consumer(builder: (context, ref, child) { return Checkbox( value: ref.watch(terminalSelected) == 3 ? true : false, materialTapTargetSize: MaterialTapTargetSize.padded, activeColor: Constants.primaryColor, shape: const CircleBorder(), side: const BorderSide( width: 2, style: BorderStyle.solid, color: Color(0xffd9d9d9), ), onChanged: (bool? value) { if (value == true) { ref .read(terminalSelected.notifier) .update((state) => 3); } }, ); }), Expanded( child: ListTile( contentPadding: EdgeInsets.zero, title: Text( 'Terminal 3', style: GoogleFonts.inter( fontSize: 18, fontWeight: FontWeight.w500, color: const Color(0xff344054), ), ), subtitle: Text( 'Pick Up Point', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w500, color: const Color(0xff344054), ), ), ), ), ], ), ), ), ], ), () {}, true, ); }); } @override void dispose() { // TODO: implement dispose super.dispose(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); // to re-show bars } @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ const GoogleMap( initialCameraPosition: CameraPosition( target: GoogleMapsConstants.terminal1Location, zoom: 18, ), ), Positioned( top: MediaQuery.of(context).viewPadding.top, child: Row( mainAxisSize: MainAxisSize.min, children: [ ElevatedButton( onPressed: () {}, clipBehavior: Clip.antiAlias, style: ElevatedButton.styleFrom( padding: EdgeInsets.zero, foregroundColor: const Color(0xff344054), backgroundColor: Colors.white, shape: const CircleBorder(), ), child: SvgPicture.asset('assets/svgs/uyufjdx.svg'), ), const SizedBox( width: 5, ), ElevatedButton( onPressed: () {}, clipBehavior: Clip.antiAlias, style: ElevatedButton.styleFrom( foregroundColor: const Color(0xff344054), backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50.0), ), ), child: SvgPicture.asset('assets/svgs/gutdw.svg'), ), ], ), ), ], ), ); } } [/code] Мне нужно нажать эти кнопки и взаимодействовать с GoogleMaps при открытом ModalBottomSheet. Поскольку мне нужно открыть ModalBottomSheet, как только откроется экран, нет возможности вручную открыть лист с помощью любой кнопки, он должен открываться автоматически при открытии этого экрана, и я должен иметь возможность взаимодействовать с фоном содержимое экрана. ИЗОБРАЖЕНИЕ: Дизайн, который мне нужно реализовать: [img]https:// i.sstatic.net/kFIXZ.jpg[/img] Подробнее здесь: [url]https://stackoverflow.com/questions/77431982/i-need-to-click-a-button-outside-the-modalbottomsheet-without-dismissing-the-bot[/url]