Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 10 months ago.
Improve this question
there!
Can anyone achieve something like this in flutter?
screen recorded video (file size too big to attach it here!)
You can change the AppBar's color by using ScrollController#addListener.
It's a simple implementation with RiverPod.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class CustomScrollViewSample extends ConsumerWidget {
const CustomScrollViewSample({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
return CustomScrollView(
controller: ref.read(controller),
slivers: [
SliverAppBar(
backgroundColor: ref.watch(backgroundColor),
foregroundColor: ref.watch(foregroundColor),
pinned: true,
elevation: 0,
title: const Text('We did it!'),
),
SliverList(
delegate: SliverChildListDelegate(
const [
SizedBox(height: 400),
SizedBox(
height: 400,
child: Card(margin: EdgeInsets.all(16), color: Colors.blue),
),
SizedBox(height: 400),
],
),
),
],
);
}
}
final controller = Provider((ref) {
final scrollController = ScrollController();
void listener() {
ref.read(backgroundOpacity.notifier).state = min(
1,
scrollController.position.pixels / 200,
);
}
scrollController.addListener(listener);
ref.onDispose(() {
scrollController.removeListener(listener);
});
return scrollController;
});
final backgroundColor = Provider(
(ref) => Colors.black.withOpacity(
ref.watch(backgroundOpacity),
),
);
final foregroundColor = Provider(
(ref) => Color.fromRGBO(
(ref.watch(backgroundOpacity) * 255).toInt(),
(ref.watch(backgroundOpacity) * 255).toInt(),
(ref.watch(backgroundOpacity) * 255).toInt(),
1,
),
);
final backgroundOpacity = StateProvider((_) => 0.0);
I also wrote the sample that works on DartPad.
If you like please try this.
https://dartpad.dev/?id=336910211bb02227e4c0b11e939aa116
Related
I want to create a dropdown menu on flutter where the handler button that opens the dropdown uses just an icon and the menu list opened by it uses an icon and a text.
I almost manage to create it, as you can check on the following screenshots:
Closed
Opened
I'm struggling with the opened width, so my question is how to give the opened menu enough width and keep the handler button on its current width.
Notice that I want the dropdown to be at the end of the Row, so consider this black box to be an area of something else, nothing important.
I'm adding the relevant code below and the complete code on the following links.
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.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: "Question Dropdown",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(
optionStream: BehaviorSubject<Option>(),
),
);
}
}
class HomePage extends StatelessWidget {
final BehaviorSubject<Option> optionStream;
const HomePage({
Key? key,
required this.optionStream,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Question Dropdown"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Expanded(
child: Container(
height: 48,
color: Colors.black,
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: StreamBuilder<Option>(
initialData: Option.A,
stream: optionStream,
builder: (context, snapshot) {
final option = snapshot.data ?? Option.A;
return _dropDownMenu(context, option);
},
),
),
],
),
],
),
),
);
}
Widget _dropDownMenu(
BuildContext context,
Option option,
) {
const items = Option.values;
return DropdownButtonHideUnderline(
child: DropdownButton<Option>(
value: option,
selectedItemBuilder: (context) =>
items.map((e) => _dropdownHandler(context, e)).toList(),
items: items.map((e) => _dropdownItem(context, e)).toList(),
onChanged: (e) => optionStream.add(e ?? Option.A),
),
);
}
OptionsItemHelper _dropDownItemData(
BuildContext context,
Option option,
) {
Widget icon;
String text;
switch (option) {
case Option.A:
icon = const Icon(Icons.ac_unit);
text = "An option";
break;
case Option.B:
icon = const Icon(Icons.baby_changing_station);
text = "Best option";
break;
case Option.C:
icon = const Icon(Icons.cake_sharp);
text = "Closest option";
break;
case Option.D:
icon = const Icon(Icons.dashboard);
text = "Dumb option";
break;
}
return OptionsItemHelper(text, icon);
}
Widget _dropdownHandler(
BuildContext context,
Option option,
) {
final helper = _dropDownItemData(context, option);
return helper.icon;
}
DropdownMenuItem<Option> _dropdownItem(
BuildContext context,
Option option,
) {
final helper = _dropDownItemData(context, option);
return DropdownMenuItem<Option>(
value: option,
child: Row(
children: [
helper.icon,
const SizedBox(width: 16),
Text(helper.text),
],
),
);
}
}
enum Option {
A,
B,
C,
D,
}
class OptionsItemHelper {
final String text;
final Widget icon;
OptionsItemHelper(
this.text,
this.icon,
);
}
Complete code on Github
Complete code on Gitlab
I did find a workaround using GestureDetector and showMenu, I'm sharing here and pushing to the repo as "workaround" commit in case you need the same as I need now, I'm keeping the question without answer in case someone finds a better way using the dropdown.
The new dropDownMenu function
Widget _dropDownMenu(
BuildContext context,
Option option,
) {
const items = Option.values;
return GestureDetector(
onTapDown: (details) async {
final offset = details.globalPosition;
final newOption = await showMenu(
context: context,
position: RelativeRect.fromLTRB(offset.dx, offset.dy, 0, 0),
items: items.map((e) => _dropdownItem(context, e, option)).toList(),
);
if (newOption != null) {
optionStream.add(newOption);
}
},
child: _dropdownHandler(context, option),
);
}
and the new dropdownItem function.
PopupMenuEntry<Option> _dropdownItem(
BuildContext context,
Option option,
Option selected,
) {
final helper = _dropDownItemData(context, option);
return CheckedPopupMenuItem<Option>(
value: option,
checked: option == selected,
child: Row(
children: [
Expanded(child: Container()),
Text(helper.text),
const SizedBox(width: 16),
helper.icon,
],
),
);
}
How it looks like
Closed
Opened
Bigger Screen
I am new in flutter development. I cannot find my mistake. I can't see my images on my app. when I use them without slider it works what is wrong in my code can someone help me?
import 'package:feedme_start/widgets/Navigation_Drawer_Widget.dart';
import 'package:flutter/material.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:flutter_swiper/flutter_swiper.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
final imageList = [
"https://cdn.yeniakit.com.tr/images/news/625/pratik-degisik-yemek-tarifleri-en-sevilen-tarifler-h1581081558-3ff37b.jpg"
"https://cdn.yemek.com/mncrop/940/625/uploads/2021/04/patlicanli-pilav-yemekcom.jpg"
];
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.red,
title: Center(child: Text("FEED ME")),
actions: <Widget>[
IconButton(onPressed: () {}, icon: Icon(Icons.call))
],
),
drawer: NavigationDrawerWidget(),
backgroundColor: Colors.white,
body:
Container(
constraints: BoxConstraints.expand(height: 200),
child: imageSlider(context),
),
/*Swiper(itemCount: imageList.length,
itemBuilder: (context, index) {
return Image.network(imageList[index],/*errorBuilder:
(BuildContext context, Object exception, StackTrace? stackTrace), {return const("resim yüklenemedi")},*/
fit: BoxFit.cover,);
},)*/
),
);
}
}
Swiper imageSlider(context){
return new Swiper(
autoplay: true,
itemBuilder: (BuildContext context, int index) {
return new Image.network("https://cdn.yeniakit.com.tr/images/news/625/pratik-degisik-yemek-tarifleri-en-sevilen-tarifler-h1581081558-3ff37b.jpg",fit: BoxFit.fitHeight,);
},
itemCount: 10,
viewportFraction: 0.8,
scale: 0.9,
);
}
also here is the screenshots;
when I run the program it tries to upload the image. then it sends me the this screen and shows the 'rethrow' line error:
after I continue debugging my screen looks like in the second picture:
You're simply forgetting to add , in your list.
A newline string after a string is considered as a string. For example, the following variable:
var text = "one two three"
"four five six";
is the same as:
var text = "one two three" + "four five six";
So, instead of:
final imageList = [
"https://cdn.yeniakit.com.tr/images/news/625/pratik-degisik-yemek-tarifleri-en-sevilen-tarifler-h1581081558-3ff37b.jpg"
"https://cdn.yemek.com/mncrop/940/625/uploads/2021/04/patlicanli-pilav-yemekcom.jpg"
];
change to:
final imageList = [
"https://cdn.yeniakit.com.tr/images/news/625/pratik-degisik-yemek-tarifleri-en-sevilen-tarifler-h1581081558-3ff37b.jpg" ,
"https://cdn.yemek.com/mncrop/940/625/uploads/2021/04/patlicanli-pilav-yemekcom.jpg"
];
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to show data like this:
Burger..........................$9.99
Steak and Potato...............$14.99
Mac and Cheese..................$6.99
How can I implement it in Flutter?
as an option
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) => MaterialApp(home: Home());
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Row(
children: [
Text('Burger'),
Expanded(child: Text('.' * 100, maxLines: 1)),
Text('\$9.99'),
],
),
);
}
}
I personally use fDottedLine package https://pub.dev/packages/fdottedline to draw a dotted line in any form.
: Row(
children: [
Text('Burger'),
FDottedLine(
color: Colors.black,
width: 160.0,
strokeWidth: 2.0,
dottedLength: 10.0,
space: 2.0,
),
Text('\$9.99'),
],
),
You have to give the dynamic widgth using MediaQuery
I have a Home Screen Widget, that plays a fullscreen background video using the video_player package.
This code works fine for me:
class HomeScreen extends StatefulWidget {
HomeScreen({Key key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
VideoPlayerController _controller;
void initState() {
super.initState();
// Pointing the video controller to mylocal asset.
_controller = VideoPlayerController.asset("assets/waterfall.mp4");
_controller.initialize().then((_) {
// Once the video has been loaded we play the video and set looping to true.
_controller.play();
_controller.setLooping(true);
// Ensure the first frame is shown after the video is initialized.
setState(() {});
});
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Stack(
children: <Widget>[
SizedBox.expand(
child: FittedBox(
// If your background video doesn't look right, try changing the BoxFit property.
// BoxFit.fill created the look I was going for.
fit: BoxFit.fill,
child: SizedBox(
width: _controller.value.size?.width ?? 0,
height: _controller.value.size?.height ?? 0,
child: VideoPlayer(_controller),
),
),
),
Container(
child: Center(
child: Text('Hello!'),
),
),
],
),
),
);
}
}
The question is, how can I implement this using flutter Hooks? I understand that I have to use useEffect() to implement the functionality of initState() and dispose(), useFuture() and maybe useMemoized() to handle asynchronous _controller.initialize() call and what possibly else? But, I cannot glue them to get the desired result. Can anyone indicate to me the "using Hooks" implementation of the above code?
I was looking for the answer to how to convert a VideoPlayer demo from StatefulWidget to HookWidget when I came across this question. I've come up with something that works so I'll post it here since there is nothing elsewhere that I could find and some others are hitting this page looking for an answer.
I used a viewmodel. The video controller is a property of the viewmodel. This code will not compile since some of the controls are not included. But it will demonstrate the structure and incorporation of the viewmodel.
Here's the widget file:
import 'package:flutter/foundation.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:video_player/video_player.dart';
import 'intro_viewmodel.dart';
class IntroPage extends HookWidget {
Future<void> saveAndGetStarted(BuildContext context) async {
final IntroViewModel introViewModel = context.read(introViewModelProvider);
await introViewModel.completeIntro();
}
Future<void> onNext(BuildContext context) async {
final IntroViewModel introViewModel = context.read(introViewModelProvider);
await introViewModel.incrementIntro();
}
final List<SliderModel> slides = [
SliderModel(
description: 'A word with you before you get started.\n',
title: 'Why This App?',
localImageSrc: 'media/Screen1-Movingforward-pana.svg',
backgroundColor: Colors.lightGray),
SliderModel(
description: 'This information will help the app be more accurate\n',
title: 'Personal Profile',
localImageSrc: 'media/Screen2-Teaching-cuate.svg',
backgroundColor: Colors.lightGray)
];
#override
Widget build(BuildContext context) {
final IntroViewModel introViewModel = context.read(introViewModelProvider);
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
children: [
Text(
slides[introViewModel.index].description,
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
Expanded(
child: FractionallySizedBox(
widthFactor: .98,
heightFactor: .5,
child: VideoPlayer(introViewModel.videoController),
)),
Align(
alignment: Alignment.bottomCenter,
child: CustomRaisedButton(
onPressed: () {
if (introViewModel.index == slides.length - 1) {
saveAndGetStarted(context);
} else {
onNext(context);
}
},
color: Theme.of(context).accentColor,
borderRadius: 15,
height: 50,
child: Text(
introViewModel.index == 0
? 'Continue'
: 'Save and Get Started',
style: Theme.of(context)
.textTheme
.headline5
.copyWith(color: Colors.white),
),
),
),
],
),
),
));
}
#override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IterableProperty<SliderModel>('slides', slides));
}
}
And here is the viewmodel code
import 'package:flutter/foundation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:video_player/video_player.dart';
import '../top_level_providers.dart';
final introViewModelProvider = ChangeNotifierProvider<IntroViewModel>((ref) {
//this singleton class provides global access to selected variables
final SharedPreferencesService localSharedPreferencesService =
ref.watch(sharedPreferencesService);
return IntroViewModel(localSharedPreferencesService);
});
class IntroViewModel extends ChangeNotifier {
IntroViewModel(this.localSharedPreferencesService) : super() {
state = localSharedPreferencesService?.isIntroComplete();
// Pointing the video controller to my local asset.
videoController = VideoPlayerController.asset('media/test_search.mp4');
videoController.initialize().then((_) {
// Once the video has been loaded we play the video and set looping to true.
// not autoplaying yet
// videoController.play();
// videoController.setLooping(true);
});
}
final SharedPreferencesService localSharedPreferencesService;
VideoPlayerController videoController;
bool state = false;
int index = 0;
Future<void> completeIntro() async {
await localSharedPreferencesService.setIntroComplete();
state = true;
notifyListeners();
}
Future<void> incrementIntro() async {
++index;
notifyListeners();
}
bool get isIntroComplete => state;
}
With the code below
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) => MaterialApp(
home: const MyHomePage(),
);
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) => DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Center(
child: Text('use the mouse wheel to scroll')),
bottom: TabBar(
tabs: const [
Center(child: Text('ScrollView')),
Center(child: Text('PageView'))
],
),
),
body: TabBarView(
children: [
SingleChildScrollView(
child: Column(
children: [
for (int i = 0; i < 10; i++)
Container(
height: MediaQuery.of(context).size.height,
child: const Center(
child: FlutterLogo(size: 80),
),
),
],
),
),
PageView(
scrollDirection: Axis.vertical,
children: [
for (int i = 0; i < 10; ++i)
const Center(
child: FlutterLogo(size: 80),
),
],
),
],
),
),
);
}
You can see, running it on dartpad or from this video,
that using the mouse wheel to scroll a PageView provides a mediocre experience (at best),
This is a known issue #35687 #32120, but I'm trying to find a workaround
to achieve either smooth scrolling for the PageView or at least prevent the "stutter".
Can someone help me out or point me in the right direction?
I'm not sure the issue is with PageScrollPhysics;
I have a gut feeling that the problem might be with WheelEvent
since swiping with multitouch scroll works perfectly
The problem arises from chain of events:
user rotate mouse wheel by one notch,
Scrollable receives PointerSignal and calls jumpTo method,
_PagePosition's jumpTo method (derived from ScrollPositionWithSingleContext) updates scroll position and calls goBallistic method,
requested from PageScrollPhysics simulation reverts position back to initial value, since produced by one notch offset is too small to turn the page,
another notch and process repeated from step (1).
One way to fix issue is perform a delay before calling goBallistic method. This can be done in _PagePosition class, however class is private and we have to patch the Flutter SDK:
// <FlutterSDK>/packages/flutter/lib/src/widgets/page_view.dart
// ...
class _PagePosition extends ScrollPositionWithSingleContext implements PageMetrics {
//...
// add this code to fix issue (mostly borrowed from ScrollPositionWithSingleContext):
Timer timer;
#override
void jumpTo(double value) {
goIdle();
if (pixels != value) {
final double oldPixels = pixels;
forcePixels(value);
didStartScroll();
didUpdateScrollPositionBy(pixels - oldPixels);
didEndScroll();
}
if (timer != null) timer.cancel();
timer = Timer(Duration(milliseconds: 200), () {
goBallistic(0.0);
timer = null;
});
}
// ...
}
Another way is to replace jumpTo with animateTo. This can be done without patching Flutter SDK, but looks more complicated because we need to disable default PointerSignalEvent listener:
import 'dart:async';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class PageViewLab extends StatefulWidget {
#override
_PageViewLabState createState() => _PageViewLabState();
}
class _PageViewLabState extends State<PageViewLab> {
final sink = StreamController<double>();
final pager = PageController();
#override
void initState() {
super.initState();
throttle(sink.stream).listen((offset) {
pager.animateTo(
offset,
duration: Duration(milliseconds: 200),
curve: Curves.ease,
);
});
}
#override
void dispose() {
sink.close();
pager.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Mouse Wheel with PageView'),
),
body: Container(
constraints: BoxConstraints.expand(),
child: Listener(
onPointerSignal: _handlePointerSignal,
child: _IgnorePointerSignal(
child: PageView.builder(
controller: pager,
scrollDirection: Axis.vertical,
itemCount: Colors.primaries.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(color: Colors.primaries[index]),
);
},
),
),
),
),
);
}
Stream<double> throttle(Stream<double> src) async* {
double offset = pager.position.pixels;
DateTime dt = DateTime.now();
await for (var delta in src) {
if (DateTime.now().difference(dt) > Duration(milliseconds: 200)) {
offset = pager.position.pixels;
}
dt = DateTime.now();
offset += delta;
yield offset;
}
}
void _handlePointerSignal(PointerSignalEvent e) {
if (e is PointerScrollEvent && e.scrollDelta.dy != 0) {
sink.add(e.scrollDelta.dy);
}
}
}
// workaround https://github.com/flutter/flutter/issues/35723
class _IgnorePointerSignal extends SingleChildRenderObjectWidget {
_IgnorePointerSignal({Key key, Widget child}) : super(key: key, child: child);
#override
RenderObject createRenderObject(_) => _IgnorePointerSignalRenderObject();
}
class _IgnorePointerSignalRenderObject extends RenderProxyBox {
#override
bool hitTest(BoxHitTestResult result, {Offset position}) {
final res = super.hitTest(result, position: position);
result.path.forEach((item) {
final target = item.target;
if (target is RenderPointerListener) {
target.onPointerSignal = null;
}
});
return res;
}
}
Here is demo on CodePen.
Quite similar but easier to setup:
add smooth_scroll_web ^0.0.4 to your pubspec.yaml
...
dependencies:
...
smooth_scroll_web: ^0.0.4
...
Usage:
import 'package:smooth_scroll_web/smooth_scroll_web.dart';
import 'package:flutter/material.dart';
import 'dart:math'; // only for demo
class Page extends StatefulWidget {
#override
PageState createState() => PageState();
}
class PageState extends State<Page> {
final ScrollController _controller = new ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SmoothScroll Example"),
),
body: SmoothScrollWeb(
controller: controller,
child: Container(
height: 1000,
child: ListView(
physics: NeverScrollableScrollPhysics(),
controller: _controller,
children: [
// Your content goes here, thoses children are only for demo
for (int i = 0; i < 100; i++)
Container(
height: 60,
color: Color.fromARGB(1,
Random.secure().nextInt(255),
Random.secure().nextInt(255),
Random.secure().nextInt(255)),
),
],
),
),
),
);
}
}
Thanks you hobbister !
Refer to flutter's issue #32120 on Github.
I know that it has been almost 1.5 year from this question, but I found a way that works smoothly. Maybe this will be very helpful whoever read it. Add a listener to your pageview controller with this code (You can make adjustments on duration or nextPage/animateToPage/jumpToPage etc.):
pageController.addListener(() {
if (pageController.position.userScrollDirection == ScrollDirection.reverse) {
pageController.nextPage(duration: const Duration(milliseconds: 60), curve: Curves.easeIn);
} else if (pageController.position.userScrollDirection == ScrollDirection.forward) {
pageController.previousPage(duration: const Duration(milliseconds: 60), curve: Curves.easeIn);
}
});
The issue is with the user settings, how the end-user has set the scrolling to happen with his mouse. I have a Logitech mouse that allows me to turn on or off the smooth scrolling capability via Logitech Options. When I enable smooth scrolling it works perfectly and scrolls as required but in case of disabling the smooth scroll it gets disabled on the project as well. The behavior is as set by the end-user.
Still, if there's a requirement to force the scroll to smooth scroll than can only be done by setting relevant animations. There's no direct way as of now.