Lost FloatingActionButton State when change Portrait to Landsacpe - flutter

I'm building an apps, that contain floatingactionbutton which I made with my own custom, when it pressed it shows 3 menu icons below it.
There are 2 problems:
When the orientation change to landscape, and we press floatingactionbutton it won't show instead of it will show when we press long, continue no 2
In current landscape it shows with long press like I said in no 1, and when we back again to portrait it need long press again to make it show
I've been trying some ways to make it fix, but it still doesn't work.
Here's the code and screenshot
When portrait menu show up
When changing to landscape, menu icons are missing and need long press to make it show
for floatingActionButton
floatingActionButton: OrientationBuilder(
builder: (BuildContext context, Orientation orientation){
return orientation == Orientation.landscape
? _buildMenu(context)
: _buildMenu(context);
},
),
_buildMenu() that call floatingActionButton
Widget _buildMenu(BuildContext context){
final icons = [ Icons.swap_vert, Icons.check_circle_outline, Icons.filter_list ];
var nowOrientation = MediaQuery.of(context).orientation;
var b = Container(
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints){
return OverlayBuilder(
showOverlayTrue: true,
overlayBuild: (BuildContext overlayContext){
RenderBox box = context.findRenderObject() as RenderBox;
final center = box.size.center(box.localToGlobal(const Offset(0.8, 0.8)));
return new Positioned(
top: Offset(center.dx, center.dy - icons.length * 35.0).dy,
left: Offset(center.dx, center.dy - icons.length * 35.0).dx,
child: new FractionalTranslation(
translation: const Offset(-0.5, -0.6),
child: FabIcons(
icons: icons,
),
),
);
},
);
},
),
);}
To make it simple in viewing I put some code on github
OverlayBuilder Class https://github.com/ubaidillahSriyudi/StackOverflowhelp/blob/master/OverlayBuilderClass
Fabicons Class
https://github.com/ubaidillahSriyudi/StackOverflowhelp/blob/master/FabIcons
Thanks so much to someone that could help it

Happens because every time you change orientation, your FloatingActionButton rebuilds and loses state.
You should find a way to save the state of FabIcons widget.
Simple solution :
Constructing FabIcons widget with
icons,
iconTapped;
These variables should be saved in the Parent Widget, so every time you call _buildMenu(context); you pass in those variables

Related

flutter camera - what is the difference between CameraPreview(controller) and controller.buildPreiview()

I am new to flutter and I am trying to use camera with flutter.
I want to understand the difference between CameraPreview(controller) and controller.buildPreiview() because it behaves differently for some reason.
This is the code for the showing the preview:
#override
Widget build(BuildContext context) {
return _isCameraInitialized
? Material(
child: Stack(
children: [
GestureDetector(
...
child: _cameraController!.buildPreview()
// child: CameraPreview(_cameraController!)
),
....
]
),
)
: Container();
The result for using _cameraController!.buildPreview():
This is the desired result - make the camera preview appear as full screen.
But the result for using CameraPreview(_cameraController!) is:
This leaves the right of the screen white and does not take the full width of the screen for some reason. I also tried to wrap it with AspectRatio but it didn't work.
I was wondering why those methods behave differently and if it is better to use one of them over the other?
use this solution it will remove the right vertical banner :
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child:CameraPreview(_cameraController),

How to auto pause video when scrolling / when the player is not visible on screen in flutter

I am working with a video player called 'flick video player'. I can play videos fairly okay with default functionality. The problem occurs when I scroll down the screen and the video continues to play in the background. I would like to pause it when it isn't visible, or when a user navigates to a different page on the project app.
The video player that I am using (flick_video_player) has video_player as its dependency.
Answers are much appreciated.
Regards
I think you can use visibility detector for the purpose-
VisibilityDetector(
key: ObjectKey(flickManager),
onVisibilityChanged: (visibility){
if (visibility.visibleFraction == 0 && this.mounted) {
flickManager?.flickControlManager?.pause();//pausing functionality
}
},
child: Container(
child: AspectRatio(
aspectRatio: 1280/720,
child: FlickVideoPlayer(
flickManager: flickManager
),
/*VideoPlayer(
video_controller
),*/
),
),
),
I was working on something similar. For more info like how to play it again and more you can refer this repo- https://github.com/GeekyAnts/flick-video-player/tree/master/example/lib/feed_player
Hope it helped!
Maybe this visibility detector package can help https://pub.dev/packages/visibility_detector
Wrap your list of videos with a NotificationListener and listen to whether the user has started or stopped scrolling. Use this value to either play or pause your video.
Edit: misread your question. This will work for pausing once the user scrolls. If you want to detect whether the video is within the current view, check out ScrollablePositionedList.
return NotificationListener(
onNotification: (notificationInfo) {
if (notificationInfo is ScrollStartNotification) {
// Set a state value to indicate the user is scrolling
}
if (notificationInfo is ScrollEndNotification) {
// Set a state value to indicate the user stopped scrolling
}
return true;
},
child: YourVideos(),
);
This is exactly what you need, inview_notifier_list:
InViewNotifierList(
isInViewPortCondition:
(double deltaTop, double deltaBottom, double vpHeight) {
return deltaTop < (0.5 * vpHeight) && deltaBottom > (0.5 * vpHeight);
},
itemCount: 10,
builder: (BuildContext context, int index) {
return InViewNotifierWidget(
id: '$index',
builder: (BuildContext context, bool isInView, Widget child) {
return Container(
height: 250.0,
color: isInView ? Colors.green : Colors.red,
child: Text(
isInView ? 'Is in view' : 'Not in view',
),
);
},
);
},
);

MiniPlayer shows only when toggling between tabs in Flutter

I have created a Miniplayer in Flutter which looks like this:
Miniplayer(
controller: miniplayerController,
minHeight: 60,
onDismissed: (){
context.read(selectedVideoProvider).state = null;
},
maxHeight: size.height - topPadding - 60,
builder: (height, percentage){
if (selectedVideo == null) {
return const SizedBox.shrink();
}
if (height <= size.width / 16 * 9){
return Row(
children: [
Text('This is a miniplayer'),
IconButton(
onPressed: (){
context.read(selectedVideoProvider).state = null;
},
icon: Icon(Icons.close)
)
],
);
}
return AnotherScreen();
}
);
Also as you can see I have a selectedVideoProvider StateProvider (I use flutter_riverpod for a state management). Also I wrapped my Miniplayer with a Visibility widget:
Consumer(
builder: (context, watch, _){
final selectedVideo = watch(selectedVideoProvider).state;
return Visibility(maintainState: true, visible: selectedVideo != null, child: MyMiniplayerWidget());
}
),
Here is the screen of the app:
Miniplayer appears when I click on these pictures in my ListView. When I click for the first time everything works great (miniplayer appears properly). However when i dismiss my miniplayer I can not open a new miniplayer by clicking on another picture. Only when i go to another tab (tabs are on my bottom navigation bar) and then go back to this screen the miniplayer appears with the MIN size:
But I want it to pop up when I click on the pictures. And again, when I click on the picture for the first time everything works great.
What is wrong with my code? Why miniplayer appears only when I toggle between tabs?
PS. if I make maintainState = false in my Visibility widget miniplayer appears immediately after clicking on the picture, however it appears with the MIN size, but I want it to appear in MAX size. Could you please also explain me why it doesn't work, if I make
context.read(miniPlayerControllerProvider).state.animateToHeight(state: PanelState.MAX);
this when I click on the picture (this is a StateProvider for my miniplayerController) (this line of code makes my miniplayer appear with MAX size when I click on the picture when maintainState = true in Visibility widget)?
I had the same problem with miniplayer and solved it with the following code:
Miniplayer(
valueNotifier: ValueNotifier(MediaQuery.of(context).size.height),

Killing flutter gesture

I am trying to stop a gesture from continuing if a certain criteria is met.
The scenario is the user is swiping a tab bar and if they go to the next tab and the condition is true it should disable further swiping. I have tried to put the tab bar in a stack with an Absorb pointer container on top but if they don't let go of the original gesture (i.e. they got to the new tab but didnt let go of the screen) it still allows them to drag through it.
is there anyway to stop the original swipe gesture?
i found this cancel method but i have no idea how to access it
https://api.flutter.dev/flutter/gestures/Drag/cancel.html
In your case there is no need to handle gesture out of the TabBarView simply change the ScrollPhysics.
Here a code example:
final isDisable = ValueNotifier(false);
tabController.animation?.addListener(() {
//The scrolling will be disabled if the second tab is displayed so you can
//add your own logic, may be just checking tabController.index
if (tabController.animation!.value == 1.0) {
isDisable.value = true;
}
});
return Scaffold(
body: ValueListenableBuilder(
valueListenable: isDisable,
builder: (context, bool value, child) => TabBarView(
controller: tabController,
// changing the physics to NeverScrollableScrollPhysics will disable scrolling
physics: value
? NeverScrollableScrollPhysics()
: AlwaysScrollableScrollPhysics(),
children: children,
),
),
);

How can I make a SliverAppBar that is similar to Google News?

I want a standard AppBar when the app starts, however, once the user begins scrolling I want the app bar to slide up and off the screen. However, when that happens, the status bar (on iOS) doesn't have a background. I don't want to set a constant background directly to the status bar using something like flutter_statusbarcolor because that leaves a solid color, which isn't a widget.
The only solution I have right now is to just keep the AppBar pined.
However, what I really want to do is what Google News does. The AppBar slides up almost all the way, however, it stays under the app bar with some opacity.
How Google News does it:
Is there any way to do this with Flutter and SliverAppBar without doing it a hacky way? The only thing I'm thinking is doing it with a stack, however, how would I know how to keep it under the status bar, as Android already has some opacity under the status bar.
Scroll widgets in flutter have controllers that inform what's going on with the scroll. You can get how much the sliver has been scrolled and change it's opacity, content and size accordingly. It's not going to be simple though, but take a look at ScrollController, used by the CustomScrollView.
I used OrientationBuilder widget to listen to changes in orientation, as when there are changes to the orientation the status bar hight can change.
Then I used FlutterStatusbarManager package to get the height of the status bar. FlutterStatusbarManager.getHeight is a future so it needed to be wrapped with a FutureBuilder
Here is the full example code
import 'package:flutter/material.dart';
import 'package:flutter_statusbar_manager/flutter_statusbar_manager.dart';
class FixedStatusbarBackground extends StatelessWidget {
final Widget child;
const FixedStatusbarBackground({Key key, this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
child,
OrientationBuilder(
builder: (context, Orientation orientation) => FutureBuilder<double>(
future: FlutterStatusbarManager.getHeight,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
height: snapshot.data,
color: Theme.of(context)
.appBarTheme
.color
.withOpacity(.7) //Colors.white.withOpacity(.7),
);
} else {
return Container();
}
}),
),
],
);
}
}
The child widget that is passed in is the entire CustomScrollView.