showMenu flutter: want to show items by horizontal - flutter

i want to create a menu popup horizontal when long press the icon category. i using showMenu function in flutter. but it's displayed in vertical
this is my code:
this is design i want:
I also attach my code
GestureDetector(
onTapDown: _storePosition,
onLongPress: () {
final RenderBox overlay = Overlay.of(context)!
.context
.findRenderObject() as RenderBox;
showMenu(
context: context,
position: RelativeRect.fromRect(
controller.tapPosition & const Size(40, 40),
Offset.zero & overlay.size,
),
items: [
PopupMenuItem<String>(
value: '1',
child: _category(
'assets/icons/category_apartment.png'),
),
PopupMenuItem<String>(
value: '2',
child: _category('assets/icons/category_beer.png'),
),
],
elevation: 8.0,
).then<void>(
(String? itemSelected) async {
print('itemSelected $itemSelected');
},
);
},
child: RepaintBoundary(
key: controller.globalKey,
child: Image.asset('assets/icons/icon_category.png',
height: 25.0),
),
),

You may achieve this using Overlay
Run the code below and adapt it with your code.
It creates an Overlay then adds it next to the item clicked by using context.findRenderObject() to find coordinates. Then the overlay can be removed using Overlay.remove()
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: ProfilePage(),
),
),
);
}
}
class ProfilePage extends StatelessWidget {
const ProfilePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Profile Page',
),
),
body: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
const CountryFormField(),
Text("Som Text"),
Text("Som Text"),
],
),
Text("Som Text"),
Text("Som Text"),
Text("Som Text"),
],
),
);
}
}
class CountryFormField extends StatefulWidget {
const CountryFormField({Key? key}) : super(key: key);
#override
_CountryFormFieldState createState() => _CountryFormFieldState();
}
class _CountryFormFieldState extends State<CountryFormField>
with TickerProviderStateMixin {
// focus node object to detect gained or loss on textField
final FocusNode _focusNode = FocusNode();
OverlayEntry? _overlayEntry;
GlobalKey globalKey = GlobalKey();
final LayerLink _layerLink = LayerLink();
OverlayState? overlayState;
#override
void initState() {
super.initState();
overlayState = Overlay.of(context);
WidgetsBinding.instance!.addPostFrameCallback((_) {
globalKey;
});
}
OverlayEntry _createOverlay() {
RenderBox renderBox = context.findRenderObject() as RenderBox;
var size = renderBox.size;
Offset position = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(
builder: (context) => Positioned(
top: position.dy + size.height / 2,
left: size.width,
child: Material(
elevation: 5.0,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
onTap: () {
_overlayEntry?.remove();
_overlayEntry = null;
},
child: Icon(Icons.refresh),
),
Icon(Icons.done),
Icon(Icons.close),
Icon(Icons.search),
],
),
),
));
}
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
if (_overlayEntry != null) return;
_overlayEntry = _createOverlay();
overlayState!.insert(_overlayEntry!);
},
child: const Text('SUBMIT'));
}
}

Related

Using ChangeNotifier to Update Home Widget with Button Press in Flutter

Here is the substance of my main.dart file:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Home()),
ChangeNotifierProvider(create: (_) => _HomeState()),
ChangeNotifierProvider(create: (_) => _SettingsPageState()),
],
child: MaterialApp(
title: 'My Great App',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Home(),
),
),
);
}
class BottomNavBarItemData {
String label;
IconData icon;
BottomNavBarItemData(this.label, this.icon);
}
class PageViewData {
Widget page;
PageViewData(this.page);
}
//The Main Page Class
class Home extends StatefulWidget with ChangeNotifier {
Home({super.key});
int _selectedIdx = 0;
int get selectedIdx => _selectedIdx;
late Widget _body;
void updateSelectedIndex(index) {
print('This is _selectedIdx:');
print(_selectedIdx);
_selectedIdx = index;
print('This is now _selectedIdx:');
print(_selectedIdx);
print('This is selectedIdx:');
print(selectedIdx);
notifyListeners();
}
final List<BottomNavBarItemData> navIcons = [
BottomNavBarItemData("Home", Icons.cottage),
BottomNavBarItemData("Settings", Icons.settings),
];
final List<PageViewData> pageScreens = [
PageViewData(const HomePage()),
PageViewData(SettingsPage()),
PageViewData(const SettingsPage2()),
];
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> with ChangeNotifier {
final pageTitles = ['My Home', 'My Settings', 'My Settings 2'];
int get thisSelectedIdx => widget._selectedIdx;
#override
void initState() {
print('Init State for Home');
super.initState();
}
#override
Widget build(BuildContext context) {
print('This is the top thisSelectedIdx:');
print(thisSelectedIdx);
if (thisSelectedIdx == 2) {
print('The index is now 2!');
widget._body = IndexedStack(
index: widget._selectedIdx,
children: const [
SettingsPage2(),
],
);
} else {
widget._body = IndexedStack(
index: widget._selectedIdx,
children: [
...widget.pageScreens.map((e) => e.page).toList(),
],
);
}
return Scaffold(
appBar: TopAppBar(appBarTitle: pageTitles[widget._selectedIdx]),
body: widget._body,
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: widget._selectedIdx,
onTap: (idx) => setState(() {
widget._selectedIdx = idx;
Home().updateSelectedIndex(widget._selectedIdx);
print('This is widget._selectedIdx:');
print(widget._selectedIdx);
print('This is thisSelectedIdx:');
print(thisSelectedIdx);
}),
items: widget.navIcons
.map(
(e) => BottomNavigationBarItem(
label: e.label,
icon: Icon(e.icon),
),
)
.toList(),
showSelectedLabels: true,
showUnselectedLabels: true,
backgroundColor: Colors.black,
selectedItemColor: const Color.fromARGB(255, 0, 255, 0),
unselectedItemColor: Colors.grey,
),
);
}
}
//The Reload Button Widget
class ReloadButton extends StatelessWidget {
const ReloadButton({super.key});
#override
Widget build(BuildContext context) {
return IconButton(
color: const Color.fromARGB(255, 0, 255, 0),
icon: const Icon(Icons.refresh),
tooltip: 'Refresh the Page',
onPressed: () {
print('Page Refreshed');
},
);
}
}
//The App Bar Class
class TopAppBar extends StatefulWidget implements PreferredSizeWidget {
const TopAppBar(
{super.key,
required this.appBarTitle,
this.preferredSize = const Size.fromHeight(50)});
final String appBarTitle;
#override
final Size preferredSize;
#override
State<TopAppBar> createState() => _TopAppBarState();
}
class _TopAppBarState extends State<TopAppBar> {
#override
void initState() {
print('Init State for TopAppBar');
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return AppBar(
foregroundColor: const Color.fromARGB(255, 0, 255, 0),
title: Text(widget.appBarTitle),
actions: const <Widget>[
ReloadButton(), //IconButton
], //<Widget>[]
backgroundColor: Colors.black,
automaticallyImplyLeading: false,
);
}
}
//The Home Page Class
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late final _controller = WebViewController();
int indexPosition = 0;
beginLoading(String A) {
if (!mounted) return;
setState(() {
indexPosition = 1;
});
}
completeLoading(String A) {
if (!mounted) return;
setState(() {
indexPosition = 0;
});
}
#override
void initState() {
print('Init State for Home Page');
_controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..clearCache()
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) {
beginLoading(url);
},
onPageFinished: (String url) {
completeLoading(url);
},
onWebResourceError: (WebResourceError error) {},
),
)
..loadRequest(Uri.parse('https://www.flutter.dev'));
super.initState();
}
#override
void dispose() {
super.dispose();
_controller;
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: IndexedStack(
index: indexPosition,
children: <Widget>[
WebViewWidget(controller: _controller),
Container(
color: Colors.black,
child: const Center(child: CircularProgressIndicator()),
),
],
),
);
}
}
//The Settings Page Class
class SettingsPage extends StatefulWidget with ChangeNotifier {
SettingsPage({super.key});
#override
State<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> with ChangeNotifier {
bool _thisOptionIsChecked = false;
bool _thisOption = false;
String _thisOptionText = 'Off';
#override
void initState() {
print('Init State for Settings Page');
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.selected,
MaterialState.focused,
MaterialState.pressed,
};
if (states.any(interactiveStates.contains)) {
return Colors.green;
}
return Colors.red;
}
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return Center(
child: Container(
color: Colors.black,
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 180,
child: Column(
children: const <Widget>[
Text(
'This Option',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
),
),
SizedBox(
width: 50,
child: Column(
children: <Widget>[
Checkbox(
checkColor: Colors.white,
fillColor:
MaterialStateProperty.resolveWith(getColor),
value: _thisOptionIsChecked,
onChanged: (bool? value) {
if (!mounted) return;
setState(() {
_thisOptionIsChecked = value!;
_thisOption = value;
if (_thisOption == true) {
_thisOptionText = 'On';
} else {
_thisOptionText = 'Off';
}
});
},
),
],
),
),
SizedBox(
width: 75,
child: Column(
children: <Widget>[
Text(
_thisOptionText,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
],
),
),
SizedBox(
width: 50,
child: Column(
children: const <Widget>[
Text(''),
],
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 35,
width: 120,
child: TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(
fontSize: 11, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
backgroundColor: Colors.grey,
foregroundColor: Colors.black,
),
onPressed: () {
int index = 7;
Provider.of<Home>(context, listen: false)
.updateSelectedIndex(index);
notifyListeners();
print('Open Location Settings');
},
child: const Text('My Settings 2'),
),
),
],
),
],
),
),
);
});
}
}
class SettingsPage2 extends StatefulWidget {
const SettingsPage2({super.key});
#override
State<SettingsPage2> createState() => _SettingsPage2State();
}
class _SettingsPage2State extends State<SettingsPage2> {
late var _controller = WebViewController();
int indexPosition = 0;
beginLoading(String A) {
if (!mounted) return;
setState(() {
indexPosition = 1;
});
}
completeLoading(String A) {
if (!mounted) return;
setState(() {
indexPosition = 0;
});
}
#override
void initState() {
print('Init State for My Settings Page 2');
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) {
beginLoading(url);
},
onPageFinished: (String url) {
completeLoading(url);
},
onWebResourceError: (WebResourceError error) {},
),
)
..loadRequest(Uri.parse('https://www.google.com'));
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: IndexedStack(
index: indexPosition,
children: <Widget>[
WebViewWidget(
controller: _controller,
),
Container(
color: Colors.black,
child: const Center(child: CircularProgressIndicator()),
),
],
),
);
}
}
I only have the two pages, Home and Settings, loading in my navigation menu because I want the second page of settings to remain hidden until the user taps on Settings and then presses the My Settings 2 button.
I am a bit lost using the ChageNotifier provider, which I think is what I need, and I am not sure what else to try. The main page loads with a web page and works great. The Settings page opens and works great as well. On that page, I have a button which, when pressed, should open up another page in the main window. I am using the selectedIdx and _selectedIdx variables to track movement between the pages. When I click on Home or Settings in the bottomNavigationBar, everything prints appropriately. I get the printed output I would expect:
flutter: This is _selectedIdx:
flutter: 0
flutter: This is now _selectedIdx:
flutter: 0
flutter: This is selectedIdx:
flutter: 0
flutter: This is widget._selectedIdx:
flutter: 0
flutter: This is thisSelectedIdx:
flutter: 0
flutter: This is the top thisSelectedIdx:
flutter: 0
flutter: This is _selectedIdx:
flutter: 0
flutter: This is now _selectedIdx:
flutter: 1
flutter: This is selectedIdx:
flutter: 1
flutter: This is widget._selectedIdx:
flutter: 1
flutter: This is thisSelectedIdx:
flutter: 1
flutter: This is the top thisSelectedIdx:
flutter: 1
However, when I click on the My Settings 2 button, it is not behaving the way I would expect it to. It does call the Provider.of<Home>(context, listen: false).updateSelectedIndex(index) function and passed the index of 2, but it just dies there. I get the following:
flutter: This is _selectedIdx:
flutter: 0
flutter: This is now _selectedIdx:
flutter: 2
flutter: This is selectedIdx:
flutter: 2
flutter: Open Settings Page 2
What I would expect to see is this:
flutter: This is _selectedIdx:
flutter: 0
flutter: This is now _selectedIdx:
flutter: 2
flutter: This is selectedIdx:
flutter: 2
flutter: This is widget._selectedIdx:
flutter: 2
flutter: This is thisSelectedIdx:
flutter: 2
flutter: This is the top thisSelectedIdx:
flutter: 2
flutter: Open Settings Page 2
This tells me that the Home class is not being rebuilt. So, even though the function runs, I never get an updated widget for the Home class. I am racking my brain on how to get this button to show the SettingsPage2 class. Any ideas to help get me unstuck? I thought this would be fairly simple to do, but it just doesn't work the way my mind thinks it should.

How can I scroll down and focus to a specific widget in flutter?

I am implementing a tutorial of app using https://pub.dev/packages/tutorial_coach_mark . This marked button of beyond the view. So when I need to target this button, I need to scroll/focus this specific part. But I can not find any solution. Can anyone help me with that please?
One Idea is to , Make one Listview with all your widgets . then
Use this :
scroll_to_index: ^2.1.1
Example:
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scroll To Index Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Scroll To Index Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const maxCount = 100;
static const double maxHeight = 1000;
final random = math.Random();
final scrollDirection = Axis.vertical;
late AutoScrollController controller;
late List<List<int>> randomList;
#override
void initState() {
super.initState();
controller = AutoScrollController(
viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: scrollDirection);
randomList = List.generate(maxCount,
(index) => <int>[index, (maxHeight * random.nextDouble()).toInt()]);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
IconButton(
onPressed: () {
setState(() => counter = 0);
_scrollToCounter();
},
icon: Text('First'),
),
IconButton(
onPressed: () {
setState(() => counter = maxCount - 1);
_scrollToCounter();
},
icon: Text('Last'),
)
],
),
body: ListView(
scrollDirection: scrollDirection,
controller: controller,
children: randomList.map<Widget>((data) {
return Padding(
padding: EdgeInsets.all(8),
child: _getRow(data[0], math.max(data[1].toDouble(), 50.0)),
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: _nextCounter,
tooltip: 'Increment',
child: Text(counter.toString()),
),
);
}
int counter = -1;
Future _nextCounter() {
setState(() => counter = (counter + 1) % maxCount);
return _scrollToCounter();
}
Future _scrollToCounter() async {
await controller.scrollToIndex(counter,
preferPosition: AutoScrollPosition.begin);
controller.highlight(counter);
}
Widget _getRow(int index, double height) {
return _wrapScrollTag(
index: index,
child: Container(
padding: EdgeInsets.all(8),
alignment: Alignment.topCenter,
height: height,
decoration: BoxDecoration(
border: Border.all(color: Colors.lightBlue, width: 4),
borderRadius: BorderRadius.circular(12)),
child: Text('index: $index, height: $height'),
));
}
Widget _wrapScrollTag({required int index, required Widget child}) =>
AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: child,
highlightColor: Colors.black.withOpacity(0.1),
);
}
This will work Perfectly
final dataKey = new GlobalKey();
SingleChildScrollView(
child: Column(
children: [
otherwidgets(),
otherwidgets(),
Container(
key: controller.dataKey,
child: helpPart(context),
),
otherwidgets(),
otherwidgets(),
],
),
on action: Scrollable.ensureVisible(dataKey.currentContext!);
This worked for me!

How to pass listview data while using bottom navigation bar in flutter?

I want to pass data onclick of the listview items from one screen to another. All screen has bottom navigation bar with end drawer. Tried to pass data from second screen to details screen but was unsuccessful as there is no Navigator used. Anyone can help me with this? Following is the implemented code
bottom_nav_bar.dart
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'Utility.dart';
import 'main.dart';
class CustomAnimatedBottomBar extends StatelessWidget {
CustomAnimatedBottomBar({
Key? key,
this.selectedIndex = ScreenType.home,
this.showElevation = true,
this.iconSize = 24,
this.backgroundColor,
this.itemCornerRadius = 40,
this.animationDuration = const Duration(milliseconds: 270),
this.mainAxisAlignment = MainAxisAlignment.spaceBetween,
required this.items,
required this.onItemSelected,
this.curve = Curves.linear,
}) : assert(items.length >= 2 && items.length <= 5),
super(key: key);
final ScreenType selectedIndex;
final double iconSize;
final Color? backgroundColor;
final bool showElevation;
final Duration animationDuration;
final List<BottomNavyBarItem> items;
final ValueChanged<ScreenType> onItemSelected;
final MainAxisAlignment mainAxisAlignment;
final double itemCornerRadius;
final Curve curve;
#override
Widget build(BuildContext context) {
final bgColor = backgroundColor ?? Theme.of(context).bottomAppBarColor;
return Container(
decoration: BoxDecoration(
color: bgColor,
boxShadow: [
if (showElevation)
const BoxShadow(
color: Colors.black12,
blurRadius: 2,
),
],
),
child: SafeArea(
child: Container(
width: double.infinity,
height: kToolbarHeight,
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
child: Row(
mainAxisAlignment: mainAxisAlignment,
children: items.map((item) {
var index = item;
return GestureDetector(
onTap: () => onItemSelected(index.screenType),
child: _ItemWidget(
item: item,
iconSize: iconSize,
isSelected: index.screenType == selectedIndex,
backgroundColor: bgColor,
itemCornerRadius: itemCornerRadius,
animationDuration: animationDuration,
curve: curve,
),
);
}).toList(),
),
),
),
);
}
}
class _ItemWidget extends StatelessWidget {
final double iconSize;
final bool isSelected;
final BottomNavyBarItem item;
final Color backgroundColor;
final double itemCornerRadius;
final Duration animationDuration;
final Curve curve;
const _ItemWidget({
Key? key,
required this.item,
required this.isSelected,
required this.backgroundColor,
required this.animationDuration,
required this.itemCornerRadius,
required this.iconSize,
this.curve = Curves.linear,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Semantics(
container: true,
selected: isSelected,
child: AnimatedContainer(
width: isSelected ? 130 : 50,
height: double.maxFinite,
duration: animationDuration,
curve: curve,
decoration: BoxDecoration(
color:
isSelected ? item.activeColor.withOpacity(0.2) : backgroundColor,
borderRadius: BorderRadius.circular(itemCornerRadius),
),
child: Container(
width: isSelected ? 130 : 50,
padding: EdgeInsets.symmetric(horizontal: 10),
child: Row(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
IconTheme(
data: IconThemeData(
size: iconSize,
color: isSelected
? item.activeColor.withOpacity(1)
: item.inactiveColor == null
? item.activeColor
: item.inactiveColor,
),
child: item.icon,
),
if (isSelected)
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 4),
child: DefaultTextStyle.merge(
style: TextStyle(
color: item.activeColor,
fontWeight: FontWeight.bold,
),
maxLines: 1,
textAlign: item.textAlign,
child: item.title,
),
),
),
],
),
),
),
);
}
}
class BottomNavyBarItem {
BottomNavyBarItem({
required this.screenType,
required this.icon,
required this.title,
this.activeColor = Colors.blue,
this.textAlign,
this.inactiveColor,
});
final ScreenType screenType;
final Widget icon;
final Widget title;
final Color activeColor;
final Color? inactiveColor;
final TextAlign? textAlign;
}
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/FifthScreen.dart';
import 'package:flutter_app/details_screen.dart';
import 'package:flutter_app/profile_screen.dart';
import 'package:flutter_app/secondPage.dart';
import 'ThirdPage.dart';
import 'Utility.dart';
import 'bottom_nav_bar.dart';
import 'firstpage.dart';
import 'fourthPage.dart';
import 'home_screen.dart';
import 'message_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
enum ScreenType {
firstScreen,
secondScreen,
thirdScreen,
forthScreen,
fifthScreen,
detailsScreen,
home,
messages,
profile
}
class _MyHomePageState extends State<MyHomePage> {
ScreenType _screenType = ScreenType.home;
final _inactiveColor = Colors.grey;
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: getTitle(_screenType),
),
endDrawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('First Screen'),
onTap: (){onTabTapped(ScreenType.firstScreen);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Second Screen'),
onTap:(){onTabTapped(ScreenType.secondScreen);
Navigator.of(context).pop();
},
),
ListTile(
title: Text('Third Screen'),
onTap: (){onTabTapped(ScreenType.thirdScreen);
Navigator.of(context).pop();
},
),
],
),
),
body: _body(_screenType),
bottomNavigationBar: _buildBottomBar(),
);
}
Widget _body(ScreenType screenType) {
switch (screenType) {
case ScreenType.firstScreen:
return FirstScreen(
navigateScreen: (screenType) => onTabTapped(screenType),
);
case ScreenType.secondScreen:
return SecondScreen(
onClickList: (model){
setState(() {
_screenType = ScreenType.detailsScreen;
});
},
);
case ScreenType.thirdScreen:
return const ThirdScreen();
case ScreenType.forthScreen:
return const ForthScreen();
case ScreenType.home:
return const HomeScreen();
case ScreenType.messages:
return const MessagesScreen();
case ScreenType.profile:
return const ProfileScreen();
case ScreenType.fifthScreen:
return const FifthScreen();
case ScreenType.detailsScreen:
return DetailsScreen();
}
}
Widget _buildBottomBar() {
return CustomAnimatedBottomBar(
backgroundColor: Colors.black,
selectedIndex: _screenType,
showElevation: true,
itemCornerRadius: 24,
curve: Curves.easeIn,
onItemSelected: onTabTapped,
items: <BottomNavyBarItem>[
BottomNavyBarItem(
screenType: ScreenType.home,
icon: Icon(Icons.apps),
title: Text('Home'),
activeColor: Colors.green,
inactiveColor: _inactiveColor,
textAlign: TextAlign.center,
),
BottomNavyBarItem(
screenType: ScreenType.messages,
icon: Icon(Icons.message),
title: Text('Messages'),
activeColor: Colors.purpleAccent,
inactiveColor: _inactiveColor,
textAlign: TextAlign.center,
),
BottomNavyBarItem(
screenType: ScreenType.profile,
icon: Icon(Icons.account_circle_rounded),
title: Text('Profile'),
activeColor: Colors.pink,
inactiveColor: _inactiveColor,
textAlign: TextAlign.center,
),
],
);
}
void onTabTapped(ScreenType screenType) {
if ((_scaffoldKey.currentState ?? ScaffoldState()).isEndDrawerOpen) {
(_scaffoldKey.currentState ?? ScaffoldState()).openEndDrawer();
}
setState(() {
_screenType = screenType;
});
}
Widget getTitle(ScreenType screenType) {
switch (screenType) {
case ScreenType.firstScreen:
return Text("First Screen");
case ScreenType.secondScreen:
return Text("Second Screen");
case ScreenType.thirdScreen:
return Text("Third Screen");
case ScreenType.forthScreen:
return Row(
children: [
IconButton(onPressed: (){
onTabTapped(ScreenType.firstScreen);
}, icon: Icon(Icons.arrow_back_ios)),
Text("Fourth Screen"),
],
);
case ScreenType.detailsScreen:
return Text("Details Screen");
case ScreenType.home:
return Text("Home");
case ScreenType.messages:
return Text("Message");
case ScreenType.profile:
return Text("Profile");
case ScreenType.fifthScreen:
// TODO: Handle this case.
return Text("Fifth Sceen");
break;
}
}
}
second_page.dart
import 'package:flutter/material.dart';
typedef OnClickList(Model);
class SecondScreen extends StatefulWidget {
// final VoidCallback voidCallback;
final OnClickList onClickList;
const SecondScreen({Key? key, required this.onClickList}) : super(key: key);
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
Widget build(BuildContext context) {
List<Model> items = [
Model(text: "Text 1 to next screen"),
Model(text: "Text 2 to next screen"),
Model(text: "Text 3 to next screen"),
];
return Container(
child: Center(
child: Column(
children: [
Text("Second Screen"),
ListView.builder(
itemCount: items.length,
shrinkWrap: true,scrollDirection: Axis.vertical,
itemBuilder: (context, index){
Model model = items[index];
return GestureDetector(
onTap: (){
widget.onClickList(model.text);
},
child: Card(
child: Text("${items[index].text}"),
),
);
})
],
),
),
);
}
}
class Model{
String text;
Model({required this.text});
}
details_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/secondPage.dart';
class DetailsScreen extends StatefulWidget {
final Model? model;
const DetailsScreen({Key? key, this.model}):super(key:key);
#override
_DetailsScreenState createState() => _DetailsScreenState();
}
class _DetailsScreenState extends State<DetailsScreen> {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(widget.model!.text.toString()),
),
);
}
}
first_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';
typedef NavigateScreen(ScreenType);
class FirstScreen extends StatefulWidget {
const FirstScreen({
Key? key,
required this.navigateScreen,
}) : super(key: key);
final NavigateScreen navigateScreen;
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("First Screen"),
ElevatedButton(
onPressed: () => widget.navigateScreen(ScreenType.forthScreen),
child: Text("Go To Forth Screen"),
),
ElevatedButton(
onPressed: () => widget.navigateScreen(ScreenType.fifthScreen),
child: Text("Go To Fifth Screen"),
),
],
),
),
);
}
}
To pass data from second screen to details screen:
Add a variable in homepage state which can take content clicked from second screen.
class _MyHomePageState extends State<MyHomePage> {
ScreenType _screenType = ScreenType.home;
final _inactiveColor = Colors.grey;
Model? fromSecond;
…….
}
Change onClickList implementation and switch case.
Widget _body(ScreenType screenType) {
switch (screenType) {
case ScreenType.firstScreen:
return FirstScreen(
navigateScreen: (screenType) => onTabTapped(screenType),
);
case ScreenType.secondScreen:
return SecondScreen(
onClickList: (model) {
fromSecond = model;
setState(() {
_screenType = ScreenType.detailsScreen;
});
},
);
……..
…….
case ScreenType.detailsScreen:
{
if(fromSecond!=null) {
return DetailsScreen(model: fromSecond);
} else {
return DetailsScreen();
}
}
………..
……….
}
On SecondScreen make gesture detector return model to onClickList callback.
…………
…………
return GestureDetector(
onTap: (){
widget.onClickList(model);
},
child: Card(
child: Text("${items[index].text}"),
),
);
…….
…….

How change the Icon of an IconButton when it is pressed

I want to know how I can change the Icon of an IconButton when it is pressed. (Favorite_border to Favorite). I tried somethings but it doesn't works.
Maybe it is easy but I am a beginner and I don't understand very well how it is works.
Update
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../recyclerview/data.dart';
import 'package:watch/constants.dart';
int itemCount = item.length;
List<bool> selected = new List<bool>();
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
for (var i = 0; i < itemCount; i++) {
selected.add(false);
}
super.initState();
}
Icon notFavorite = Icon(Icons.favorite_border, size: 25,);
Icon inFavorite = Icon(Icons.favorite, size: 25,);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil', style: kAppBarStyle,),
//backgroundColor: Colors.white,
elevation: 0,
),
body: ListView.builder(
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) {
return Container(
child: new Row(
children: <Widget>[
//Image
new Container(
margin: new EdgeInsets.all(5.0),
child: new CachedNetworkImage(
imageUrl: item[index].imageURL,
height: MediaQuery.of(context).size.width / 4,
width: MediaQuery.of(context).size.width / 2,
fit: BoxFit.cover,
),
),
//Text
Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Spacer(),
//Titre
Container(
padding: const EdgeInsets.only(bottom: 75.0, top: 10.0 ),
child: Text(
item[index].title,
style: kItemTitle,
),
),
//Decription
Container(
padding: const EdgeInsets.only(left: 10.0, top: 10.0),
child:Text(
item[index].description,
style: kItemDescription,
),
),
//Favoris
Spacer(),
GestureDetector(
child: Container(
padding: const EdgeInsets.only(right: 10.0, top: 3.0),
child: selected.elementAt(index) ? inFavorite : notFavorite,
),
onTap: () {
setState(() {
selected[index] = !selected.elementAt(index);
});
},
),
],
),
),
],
),
);
}
)
);
}
}
It is a ListView with Images, Texts and the Favorite Button and it works fine.
First you need a boolean variable.
bool toggle = false;
After that you can use IconButton like this:
IconButton(
icon: toggle
? Icon(Icons.favorite_border)
: Icon(
Icons.favorite,
),
onPressed: () {
setState(() {
// Here we changing the icon.
toggle = !toggle;
});
}),
custom radio button (some IconButton in ListView that change their icons):
main.dart file :
import 'package:flutter/material.dart';
import 'my_home_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
my_home_page.dart file:
import 'package:flutter/material.dart';
int itemCount = 5;
List<bool> selected = new List<bool>();
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
for (var i = 0; i < itemCount; i++) {
selected.add(false);
}
super.initState();
}
Icon firstIcon = Icon(
Icons.radio_button_on, // Icons.favorite
color: Colors.blueAccent, // Colors.red
size: 35,
);
Icon secondIcon = Icon(
Icons.radio_button_unchecked, // Icons.favorite_border
color: Colors.grey,
size: 35,
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView.builder(
itemCount: itemCount,
itemBuilder: (BuildContext context, int index) {
return IconButton(
icon: selected.elementAt(index) ? firstIcon : secondIcon,
onPressed: () {
try {
// your code that you want this IconButton do
setState(() {
selected[index] = !selected.elementAt(index);
});
print('tap on ${index + 1}th IconButton ( change to : ');
print(selected[index] ? 'active' : 'deactive' + ' )');
} catch (e) {
print(e);
}
},
);
}),
),
);
}
}
Copy paste the code and it will work :)
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: HomeApp(),
);
}
}
class HomeApp extends StatefulWidget {
#override
_HomeAppState createState() => _HomeAppState();
}
class _HomeAppState extends State<HomeApp> {
// Using a Bool
bool addFavorite = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter App :)"),
),
body: Center(
child: IconButton(
icon: Icon(addFavorite ? Icons.favorite : Icons.favorite_border),
onPressed: () {
// Setting the state
setState(() {
addFavorite = !addFavorite;
});
}),
),
);
}
}
Updating the Code for ListView
class _HomeAppState extends State<HomeApp> {
// Using a Bool List for list view builder
List<bool> addFavorite = List<bool>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter App :)"),
),
body: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
// Setting a bool initially
addFavorite.add(false);
return IconButton(
icon: Icon(addFavorite.elementAt(index)
? Icons.favorite
: Icons.favorite_border),
onPressed: () {
// Setting the state
setState(() {
// Changing icon of specific index
addFavorite[index] =
addFavorite[index] == false ? true : false;
});
});
}),
);
}
}
the IconButton must be in StatefulWidget and use a flag for unselected icon and selected icon:
.
.
.
bool selected = false;
Icon first_icon = Icon(...);
Icon second_icon = Icon(...);
.
.
.
IconButton(
icon: selected
? first_icon
: second_icon,
onPressed: () {
try {
// your code that you want this IconButton do
setState(() {
selected = !selected;
});
} catch(e) {
print(e);
}
}),
for use in ListView:
.
.
.
List<bool> selected = new List<bool>();
Icon first_icon = Icon(...);
Icon second_icon = Icon(...);
.
.
.
ListView.builder(
controller: scrollController,
primary: true,
...
itemCount: _yourListViewLength,
itemBuilder: (BuildContext context, int i) {
selected.add(false);
IconButton(
icon: selected.elementAt(i)
? first_icon
: second_icon,
onPressed: () {
try {
// your code that you want this IconButton do
setState(() {
selected.elementAt(i) = !selected.elementAt(i);
});
} catch(e) {
print(e);
}
}),
},
)
i hope this help you
My code if you want : home_screen.dart
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../recyclerview/data.dart';
import 'package:watch/constants.dart';
class ListViewExample extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new ListViewExampleState();
}
}
class ListViewExampleState extends State<ListViewExample>{
bool addFavorite = false;
Icon notFavorite = Icon(Icons.favorite_border, size: 25,);
Icon inFavorite = Icon(Icons.favorite, size: 25,);
List<Container> _buildListItemsFromItems(){
return item.map((item){
var container = Container(
child: new Row(
children: <Widget>[
//Image
new Container(
margin: new EdgeInsets.all(5.0),
child: new CachedNetworkImage(
imageUrl: item.imageURL,
height: MediaQuery.of(context).size.width / 4,
width: MediaQuery.of(context).size.width / 2,
fit: BoxFit.cover,
),
),
//Text
Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Spacer(),
//Titre
Container(
padding: const EdgeInsets.only(bottom: 75.0, top: 5.0 ),
child: Text(
item.title,
style: kItemTitle,
),
),
//Decription
Container(
padding: const EdgeInsets.only(left: 10.0, top: 5.0),
child:Text(
item.description,
style: kItemDescription,
),
),
//Favoris
Spacer(),
GestureDetector(
child: Container(
padding: const EdgeInsets.only(right: 10.0, top: 1.0),
child: addFavorite ? inFavorite : notFavorite,
),
onTap: () {
setState(() {
addFavorite = !addFavorite;
});
},
),
],
),
),
],
),
);
return container;
}).toList();
}
//Scaffold Global
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text('Accueil', style: kAppBarStyle,),
//backgroundColor: Colors.white,
elevation: 0,
),
body: ListView(
children: _buildListItemsFromItems(),
),
);
}
}
It is not an IconButton but just an Icon but it is working.

How to print a video path in videoplayercontroller.asset() in flutter

So I was trying to make a feature where when we click an icon button it will change the video path. It will change the video path using string. I was using a print("$videoname"), to make sure the string changes, and it does. But it still doesn't work, with the videoplayercontroller.assets():
Here's the code that I was trying to make
String videoname="Video/Intro.mp4";
Container(
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ChewieListItem(
videoPlayerController: VideoPlayerController.asset(videoname),
looping: false,
),
Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 100.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
IconButton(
icon:Icon(Icons.people),
onPressed: (){
videoname="Video/Intro.mp4";
print("$videoname");
},
),
IconButton(
icon:Icon(Icons.personal_video),
onPressed: (){
videoname="Video/Intro1.mp4";
print("$videoname");
},
),
],
),
),
)
You can copy paste run full code below
Step 1: Use key: UniqueKey() in ChewieListItem
Step 2: Use setState in onPressed
code snippet
ChewieListItem(
key: UniqueKey(),
videoPlayerController: VideoPlayerController.asset(videoname),
looping: false,
),
IconButton(
icon: Icon(Icons.people),
onPressed: () {
setState(() {
videoname = "Video/Intro.mp4";
print("$videoname");
});
},
),
IconButton(
icon: Icon(Icons.personal_video),
onPressed: () {
setState(() {
videoname = "Video/Intro1.mp4";
print("$videoname");
});
},
),
working demo
full code
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
class ChewieListItem extends StatefulWidget {
// This will contain the URL/asset path which we want to play
final VideoPlayerController videoPlayerController;
final bool looping;
ChewieListItem({
#required this.videoPlayerController,
this.looping,
Key key,
}) : super(key: key);
#override
_ChewieListItemState createState() => _ChewieListItemState();
}
class _ChewieListItemState extends State<ChewieListItem> {
ChewieController _chewieController;
#override
void initState() {
super.initState();
print("ChewieListItem initState");
// Wrapper on top of the videoPlayerController
_chewieController = ChewieController(
videoPlayerController: widget.videoPlayerController,
aspectRatio: 16 / 9,
// Prepare the video to be played and display the first frame
autoInitialize: true,
looping: widget.looping,
// Errors can occur for example when trying to play a video
// from a non-existent URL
errorBuilder: (context, errorMessage) {
return Center(
child: Text(
errorMessage,
style: TextStyle(color: Colors.white),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Chewie(
controller: _chewieController,
),
);
}
#override
void dispose() {
print("ChewieListItem dispose");
super.dispose();
// IMPORTANT to dispose of all the used resources
widget.videoPlayerController.dispose();
_chewieController.dispose();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String videoname = "Video/Intro.mp4";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
ChewieListItem(
key: UniqueKey(),
videoPlayerController: VideoPlayerController.asset(videoname),
looping: false,
),
Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 100.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
IconButton(
icon: Icon(Icons.people),
onPressed: () {
setState(() {
videoname = "Video/Intro.mp4";
print("$videoname");
});
},
),
IconButton(
icon: Icon(Icons.personal_video),
onPressed: () {
setState(() {
videoname = "Video/Intro1.mp4";
print("$videoname");
});
},
),
],
),
),
])),
);
}
}
setState should work for you
onPressed: () {
setState(() {
videoname="Video/Intro1.mp4";
print("$videoname");
});
},