Is it possible to Bring down or display the appbar only when the draggable sheet reaches the top of the page in flutter?
And having another doubt.
Is it possible to navigate from the home page to another page that has a transparent background and displays the home page as the background? Something like widgets placed on the stack...
You can add a listener to the draggableScrollableSheet and get its offset. Then based on the offset you can hide or show the Appbar.. To get a transparent screen use PageRouteBuilder with opaque: false. Check this demo
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: CustomPaintIssue()));
class CustomPaintIssue extends StatelessWidget {
const CustomPaintIssue({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool showAppbar = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: showAppbar ? AppBar() : null,
body: Container(
child: Stack(
children: [
Center(
child: InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
opaque: false,
pageBuilder: (context, _, __) => SecondPage()));
},
child: Container(
width: 50,
height: 50,
color: Colors.blue,
),
),
),
DraggableScrollableSheet(
maxChildSize: 1,
builder: (context, scrollController) {
return SingleChildScrollView(
controller: scrollController
..addListener(() {
if (scrollController.hasClients &&
scrollController.offset > 50) {
setState(() {
showAppbar = true;
});
} else {
setState(() {
showAppbar = false;
});
}
}),
child: Container(
width: MediaQuery.of(context).size.width,
height: 1500,
color: Colors.red,
),
);
})
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Column(
children: List.generate(
5,
(index) => Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: MediaQuery.of(context).size.width,
height: 50,
color: Colors.green,
)),
),
),
);
}
}
Related
I have an application that plays videos from youtube using the YoutubePlayer library. The problem is that when I go to FullScreen the application restarts and is displayed in landscape mode.
VideoView.dart
class VideoView extends StatefulWidget {
final String videoID;
const VideoView({super.key, required this.videoID});
#override
State<VideoView> createState() => _VideoView();
}
class _VideoView extends State<VideoView> {
late YoutubePlayerController _controller;
#override
void initState() {
super.initState();
_controller = YoutubePlayerController(
initialVideoId: widget.videoID,
flags: const YoutubePlayerFlags(
useHybridComposition: false,
mute: false,
autoPlay: false,
disableDragSeek: false,
loop: false,
isLive: false,
forceHD: true,
enableCaption: false,
controlsVisibleAtStart: true,
),
);/*..addListener(listener);
_videoMetaData = const YoutubeMetaData();
_playerState = PlayerState.unknown;*/
}
#override
Widget build(BuildContext context) {
return YoutubePlayerBuilder(
player: YoutubePlayer(
controller: _controller,
),
builder: ((context, player) {
return Container(
width: 100.w,
height: 100.h,
color: Colors.black,
child: player,
);
})
);
}
}
HomePage.dart
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
#override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getAllMatchData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return MaterialApp(
useInheritedMediaQuery: true,
navigatorKey: SplashScreen.navigatorKey,
initialRoute: '/',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/' :
return MaterialPageRoute(builder: (context) => HomePage(page_index: 2,));
case '/notification-page' :
return MaterialPageRoute(builder: (context) => HomePage(page_index: 2,));
case '/basic_channel' :
return MaterialPageRoute(builder: (context) => HomePage(page_index: 1,));
}
},
);
} else {
return Scaffold(
backgroundColor: HexColor("#f2f2f2"),
body: Container(
width: 100.w,
height: 100.h,
color: HexColor("#f2f2f2"),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(top: 20.h),
child: Container(width: 60.w, child: Image(image: AssetImage("assets/images/logo1.png"), fit: BoxFit.fitWidth,)),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 30.h, 0, 0.h),
child: LoadingAnimationWidget.inkDrop(
color: Colors.red,
size: 10.w,),
)
],
),
),
);
}
}
);
After a few hours, I found out that this problem only happens when the entire application is built on the MaterialApp Widget. When I changed the Widget, the FullScreen mode worked fine.
I am currently working in a page where I have to show a list of apps in the device which should be half a screen only, for that i have a used a bottom drawer widget to display that ,
the main problem is every time i open the app it needs to get pulled, i don't want to do it so can some help me to display the apps without pulling the bottom drawer widget ? or else is there any other widget to do that ?
You can try bottom modal sheet or draggableScrollableSheet which has a min size
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text('showModalBottomSheet'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.amber,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Modal BottomSheet'),
ElevatedButton(
child: const Text('Close BottomSheet'),
onPressed: () => Navigator.pop(context),
)
],
),
),
);
},
);
},
),
);
}
}
draggableScrollableSheet
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('DraggableScrollableSheet'),
),
body: SizedBox.expand(
child: DraggableScrollableSheet(
builder: (BuildContext context, ScrollController scrollController) {
return Container(
color: Colors.blue[100],
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
),
);
},
),
),
);
}
}
You can use DraggableScrollableSheet with minChildSize: .5, on this case.
return Scaffold(
bottomNavigationBar: DraggableScrollableSheet(
minChildSize: .5,
maxChildSize: 1,
builder: (context, scrollController) {
return Column(
children: [
Center(
child: Text("Title"),
),
Expanded(
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
),
),
],
);
},
));
More about DraggableScrollableSheet
I have a ListView containing string items. I want to make it so that ListView's items show one by one with delay. And after each item appears, I want to wait about 2 seconds with a typing indicator and then the next item will appear. How will I do? Please give me the solution. Thanks!
You can use AnimatedListView like this code below
https://www.youtube.com/watch?v=ZtfItHwFlZ8
// main.dart
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(
debugShowCheckedModeBanner: false,
title: 'Test',
theme: ThemeData(
primaryColor: Colors.green,
colorScheme:
ColorScheme.fromSwatch().copyWith(secondary: Colors.greenAccent)),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// Items in the list
final _items = ["Item 0"];
// The key of the list
final GlobalKey<AnimatedListState> _key = GlobalKey();
// Add a new item to the list
// This is trigger when the floating button is pressed
void _addItem() {
_items.insert(0, "Item ${_items.length + 1}");
_key.currentState!.insertItem(0, duration: const Duration(seconds: 1));
}
// Remove an item
// This is trigger when an item is tapped
void _removeItem(int index, BuildContext context) {
AnimatedList.of(context).removeItem(index, (_, animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
child: SizedBox(
height: 150,
child: Card(
margin: const EdgeInsets.symmetric(vertical: 20),
elevation: 10,
color: Colors.red[400],
child: const Center(
child: Text("I am going away",
style: const TextStyle(fontSize: 28)),
),
),
),
),
);
}, duration: const Duration(seconds: 1));
_items.removeAt(index);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Test list'),
actions: [
IconButton(
onPressed: _addItem,
icon: const Icon(Icons.plus_one_outlined),
)
],
),
body: AnimatedList(
key: _key,
initialItemCount: 1,
padding: const EdgeInsets.all(10),
itemBuilder: (context, index, animation) {
return SlideTransition(
key: UniqueKey(),
position: Tween<Offset>(
begin: const Offset(-1, -0.5),
end: const Offset(0, 0),
).animate(animation),
child: RotationTransition(
turns: animation,
child: SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: SizedBox(
height: 150,
child: InkWell(
onTap: () => _removeItem(index, context),
child: Card(
margin: const EdgeInsets.symmetric(vertical: 20),
elevation: 10,
color: Colors.primaries[
(index * 100) % Colors.primaries.length][300],
child: Center(
child: Text(_items[index],
style: const TextStyle(fontSize: 28)),
),
),
),
),
),
),
);
},
),
);
}
}
Try wrapping your widget around this widget https://pub.dev/packages/delayed_display. Please confirm if this works.
In my app I am trying to implement Badoo-like sort/filter showBottomModalSheet feature. I managed to create 2 separate pages, which I can navigate back and forth. However, the problem I'm facing is the second page in showBottomModalSheet. Back button works fine until I try to touch outside of the modal, which takes back to the first page. Instead it should close modal.
User navigates to sort users modal, which shows the 1st page in showBottomModalSheet When user taps "Show gender" it navigates to the second page (the one with different genders). When back button is pressed it navigates to 1st screen until it closes modal completely. Touching outside of the modal also closes the modal
The best stackoverflow answer that I tried:
https://stackoverflow.com/questions/63602999/how-can-i-do-navigator-push-in-a-modal-bottom-sheet-only-not-the-parent-page/63603685#63603685
I also tried using modal_bottom_sheet package, but had no luck.
https://pub.dev/packages/modal_bottom_sheet/example
Most of my code behind showBottomModalSheet:
class Page1 extends StatefulWidget {
const Page1({
Key? key
}) : super(key: key);
#override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
int _currentView = 0;
late List<Widget> pages;
#override
void initState() {
pages = [
page1(),
page2(),
];
super.initState();
}
#override
Widget build(BuildContext context) {
print("LOG build _currentView ${_currentView}");
return pages[_currentView];
}
Widget page1() {
return WillPopScope(
onWillPop: () async {
return true;
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60))),
height: 400,
width: double.maxFinite,
child: Center(
child: Column(
children: [
Text("First page"),
ElevatedButton(
onPressed: () {
setState(() {
_currentView = 1;
print("LOG page1 _currentView ${_currentView}");
});
},
child: Text("tap to navigate to 2nd page"),
),
],
)),
));
}
Widget page2() {
return WillPopScope(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60))),
height: 400,
width: double.maxFinite,
child: Center(
child: InkWell(
onTap: () {
setState(() {
_currentView = 0;
print("LOG page2 _currentView ${_currentView}");
});
},
child: Text("tap to navigate to 1st screen"),
),
),
),
onWillPop: () async {
print("LOG currentView jot $_currentView");
if (_currentView == 0) {
return true;
}
setState(() {
_currentView = 0;
});
return false;
});
}
}
Solution 1
Use the standard DraggableScrollableSheet or a 3rd-party widget to do it, there are a bunch of them. Here are some from https://pub.dev/
awesome_select
backdrop_modal_route
bottom_sheet_expandable_bar
bottom_sheet
cupertino_modal_sheet
modal_bottom_sheet
just_bottom_sheet
sheet
Solution 2
Anyway, if you'd like to do it manually I'd do it with Navigator.push/Navigator.pop instead with PageRouteBuilder with barrierDismissible=true.
It would like the following. Check out the live demo on DartPad.
Here's the code:
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(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _show() async {
await Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
barrierDismissible: true,
pageBuilder: (_, __, ___) => const Page1(),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: _show,
tooltip: 'Settings',
child: const Icon(Icons.settings),
),
);
}
}
class Page1 extends StatefulWidget {
const Page1({Key? key}) : super(key: key);
#override
State<Page1> createState() => _Page1State();
}
class _Page1State extends State<Page1> {
#override
Widget build(BuildContext context) {
return Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60)),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3), // changes position of shadow
),
],
),
height: 400,
width: double.maxFinite,
child: Center(
child: Material(
type: MaterialType.transparency,
child: Column(
children: [
const Text("First page"),
ElevatedButton(
onPressed: () async {
final backButton =
await Navigator.of(context).push<bool?>(
PageRouteBuilder(
opaque: false,
barrierDismissible: true,
pageBuilder: (_, __, ___) => const Page2(),
),
);
if (backButton == null || backButton == false) {
if (mounted) Navigator.of(context).pop();
}
},
child: const Text("tap to navigate to 2nd page"),
),
],
),
),
),
),
),
],
);
}
}
class Page2 extends StatelessWidget {
const Page2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topRight: Radius.circular(60), topLeft: Radius.circular(60)),
),
height: 400,
width: double.maxFinite,
child: Center(
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => Navigator.of(context).pop(true),
child: const Text("tap to navigate to 1st screen"),
),
),
),
),
);
}
}
I'm trying to make an application like Instagram. But I can't fully view the zoomed picture because of other pictures.
Codes:
List colors = [
Colors.green,
Colors.blue,
Colors.red,
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: ListView.builder(
itemCount: 3,
itemBuilder: (_, int index) {
TransformationController controller = TransformationController();
return Container(
child: InteractiveViewer(
transformationController: controller,
onInteractionEnd: (_) {
setState(() {
controller.toScene(Offset.zero);
});
},
child: ColorFiltered(
colorFilter: ColorFilter.mode(colors[index], BlendMode.color),
child: FlutterLogo(),
),
),
height: 200,
width: 200,
);
},
),
);
}
Note: I can't use widgets like stack because of listview.builder
You could either use Visibility widget or Opacity widget to change the visibility of images not being currently panned. Please see the code below I'm using AnimatedOpacity just so that the disappearance of the images does not look too sudden, but you may use Opacity widget as well.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("Flutter Demo")),
body: MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
static List colors = [
Colors.green,
Colors.blue,
Colors.red,
];
final List<double> _opacity = List.generate(colors.length, (index) => 1);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Demo"),
),
body: ListView.builder(
itemCount: 3,
itemBuilder: (_, int index) {
final TransformationController controller =
TransformationController();
return AnimatedOpacity(
opacity: _opacity[index],
duration: const Duration(milliseconds: 100),
child: Container(
child: InteractiveViewer(
transformationController: controller,
onInteractionStart: (details) {
for (int i = 0; i < _opacity.length; i++) {
_opacity[i] = i == index ? 1 : 0;
}
setState(() {});
},
onInteractionEnd: (_) {
setState(() {
_opacity.fillRange(0, _opacity.length, 1);
controller.toScene(Offset.zero);
});
},
child: ColorFiltered(
colorFilter: ColorFilter.mode(colors[index], BlendMode.color),
child: const FlutterLogo(),
),
),
height: 200,
width: 200,
),
);
},
),
);
}
}