Flutter Desktop: how to hide a window (and keep the process alive)? - linux

Is it possible to programmatically hide or close a window (not minimize), but still keep the process alive? This is similar to the hide()/show() methods in Qt and this is the standard approach in order to minimize the app to the tray.

window_manager is support show & hide window. you can try this.
https://github.com/leanflutter/window_manager

The package window_manager suggested by lijy91 didn't work out for me, because it did not work with Wayland under Fedora 36. It works perfectly on X11.
For now, I have decided to use bitsdojo_window combined with system_tray. It is definitely more than "just a window manager", but it works on my systems including Windows and MacOS.
A perfect example is already given on the example page of system_tray:
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart' hide MenuItem;
import 'package:system_tray/system_tray.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
doWhenWindowReady(() {
final win = appWindow;
const initialSize = Size(600, 450);
win.minSize = initialSize;
win.size = initialSize;
win.alignment = Alignment.center;
win.title = "How to use system tray with Flutter";
win.show();
});
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final SystemTray _systemTray = SystemTray();
final AppWindow _appWindow = AppWindow();
Timer? _timer;
bool _toogleTrayIcon = true;
#override
void initState() {
super.initState();
initSystemTray();
}
#override
void dispose() {
super.dispose();
_timer?.cancel();
}
Future<void> initSystemTray() async {
String path =
Platform.isWindows ? 'assets/app_icon.ico' : 'assets/app_icon.png';
List<String> iconList = ['darts_icon', 'gift_icon'];
final menu = [
MenuItem(label: 'Show', onClicked: _appWindow.show),
MenuItem(label: 'Hide', onClicked: _appWindow.hide),
MenuItem(
label: 'Start flash tray icon',
onClicked: () {
debugPrint("Start flash tray icon");
_timer ??= Timer.periodic(
const Duration(milliseconds: 500),
(timer) {
_toogleTrayIcon = !_toogleTrayIcon;
_systemTray.setImage(_toogleTrayIcon ? "" : path);
},
);
},
),
MenuItem(
label: 'Stop flash tray icon',
onClicked: () {
debugPrint("Stop flash tray icon");
_timer?.cancel();
_timer = null;
_systemTray.setImage(path);
},
),
MenuSeparator(),
SubMenu(
label: "Test API",
children: [
SubMenu(
label: "setSystemTrayInfo",
children: [
MenuItem(
label: 'setTitle',
onClicked: () {
final String text = WordPair.random().asPascalCase;
debugPrint("click 'setTitle' : $text");
_systemTray.setTitle(text);
},
),
MenuItem(
label: 'setImage',
onClicked: () {
String iconName = iconList[Random().nextInt(iconList.length)];
String path = Platform.isWindows
? 'assets/$iconName.ico'
: 'assets/$iconName.png';
debugPrint("click 'setImage' : $path");
_systemTray.setImage(path);
},
),
MenuItem(
label: 'setToolTip',
onClicked: () {
final String text = WordPair.random().asPascalCase;
debugPrint("click 'setToolTip' : $text");
_systemTray.setToolTip(text);
},
),
MenuItem(
label: 'getTitle [macOS]',
onClicked: () async {
String title = await _systemTray.getTitle();
debugPrint("click 'getTitle' : $title");
},
),
],
),
MenuItem(label: 'disabled Item', enabled: false),
],
),
MenuSeparator(),
MenuItem(
label: 'Exit',
onClicked: _appWindow.close,
),
];
// We first init the systray menu and then add the menu entries
await _systemTray.initSystemTray(
title: "system tray",
iconPath: path,
toolTip: "How to use system tray with Flutter",
);
await _systemTray.setContextMenu(menu);
// handle system tray event
_systemTray.registerSystemTrayEventHandler((eventName) {
debugPrint("eventName: $eventName");
if (eventName == "leftMouseDown") {
} else if (eventName == "leftMouseUp") {
_appWindow.show();
} else if (eventName == "rightMouseDown") {
} else if (eventName == "rightMouseUp") {
_systemTray.popUpContextMenu();
}
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: WindowBorder(
color: const Color(0xFF805306),
width: 1,
child: Row(
children: const [
LeftSide(),
RightSide(),
],
),
),
),
);
}
}
const backgroundStartColor = Color(0xFFFFD500);
const backgroundEndColor = Color(0xFFF6A00C);
class LeftSide extends StatelessWidget {
const LeftSide({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SizedBox(
width: 200,
child: Container(
color: const Color(0xFFFFFFFF),
child: Column(
children: [
WindowTitleBarBox(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [backgroundStartColor, backgroundEndColor],
stops: [0.0, 1.0]),
),
child: MoveWindow(),
),
),
Expanded(
child: Container(),
)
],
),
),
);
}
}
class RightSide extends StatelessWidget {
const RightSide({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: Container(
color: const Color(0xFFFFFFFF),
child: Column(
children: [
WindowTitleBarBox(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [backgroundStartColor, backgroundEndColor],
stops: [0.0, 1.0]),
),
child: Row(
children: [
Expanded(
child: MoveWindow(),
),
const WindowButtons()
],
),
),
),
],
),
),
);
}
}
final buttonColors = WindowButtonColors(
iconNormal: const Color(0xFF805306),
mouseOver: const Color(0xFFF6A00C),
mouseDown: const Color(0xFF805306),
iconMouseOver: const Color(0xFF805306),
iconMouseDown: const Color(0xFFFFD500));
final closeButtonColors = WindowButtonColors(
mouseOver: const Color(0xFFD32F2F),
mouseDown: const Color(0xFFB71C1C),
iconNormal: const Color(0xFF805306),
iconMouseOver: Colors.white);
class WindowButtons extends StatelessWidget {
const WindowButtons({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
MinimizeWindowButton(colors: buttonColors),
MaximizeWindowButton(colors: buttonColors),
CloseWindowButton(colors: closeButtonColors),
],
);
}
}

There are currently no Flutter APIs for controlling windows from Dart code. You would need to write native code to hide the window for the platform(s) you are interested in, and call it from Dart via platform channels.

Related

There is no error but favor page does not appear

the favor page does not apper , no errors but it does not work , i do the same for the top app bar and it works , please advice me and thanks . ( i add the 2 pages ,categories ,favorites , sorry i add more words to solve the question issues ........................................................................ )
import 'package:flutter/material.dart';
import 'package:meals/categeory_screens.dart';
import 'favorties.dart';
class TabsScreen extends StatefulWidget {
TabsScreen({Key? key}) : super(key: key);
#override
State<TabsScreen> createState() => _TabsScreenState();
}
class _TabsScreenState extends State<TabsScreen> {
final List _pages=[
CategoreyScreen(),
FavortiesScreen(),
];
int _select =0;
void _selectedPage(int index){
setState((){
index=_select;
});}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:const Text('meals'),),
body:_pages[_select],
bottomNavigationBar:
BottomNavigationBar(
onTap: _selectedPage,
selectedItemColor: Theme.of(context).bottomAppBarColor,
unselectedItemColor: Colors.white,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: 'categories'),
BottomNavigationBarItem( icon: Icon(Icons.star),
label: 'favor'),
],
backgroundColor: Theme.of(context).primaryColor,
),
);
}
}
Try this code.
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with
WidgetsBindingObserver {
int _selectedTabIndex = 0;
_changeIndex(int index) {
setState(() {
_selectedTabIndex = index;
print("index..." + index.toString());
});
}
List _pages = [
CategoriesScreen(),
FavorScreen(),
];
#override
void initState() {
WidgetsBinding.instance!.addObserver(this);
super.initState();
}
#override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
bottomNavigationBar: bottomNavigationBar,
),
);
}
Widget get bottomNavigationBar {
return Container(
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
child: BottomNavigationBar(
currentIndex: _selectedTabIndex,
onTap: _changeIndex,
type: BottomNavigationBarType.fixed,
selectedFontSize: 12,
unselectedFontSize: 12,
selectedItemColor: Colors.appColor,
unselectedItemColor: Colors.grey[500],
showUnselectedLabels: true,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: _selectedTabIndex == 0
? Icon(
Icons.local_mall,
size: 22.0,
color: Colors.appColor,
)
: Icon(
Icons.local_mall_outlined,
size: 22.0,
color: Colors.colorBlack100,
),
label: "Categories",
),
BottomNavigationBarItem(
icon: _selectedTabIndex == 1
? Icon(
Icons.dashboard,
size: 22.0,
color: Colors.appColor,
)
: Icon(
Icons.dashboard_outlined,
size: 22.0,
color: Colors.colorBlack100,
),
label: "Favor",
),
],
),
));
}
}

Is there any way to make such design in Flutter

As shown in the below Image.
I want an image at the bottom of the stack, a container above it and a transparent text widget above them. I'm unable to figure out any solution, please help!
Found a solution, works like a charm
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
class Penumbra extends StatefulWidget {
Penumbra({Key key}) : super(key: key);
#override
_PenumbraState createState() => _PenumbraState();
}
class _PenumbraState extends State<Penumbra> {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
body: Stack(
children: [
Row(
children: [
Container(
width: size.width / 2,
height: double.maxFinite,
color: Color(0xff181818),
),
Container(
width: size.width / 2,
height: double.maxFinite,
color: Colors.white,
)
],
),
SingleChildScrollView(
child: Column(
children: [
Container(
height: size.height,
),
ImageShaderWidget(),
Container(
height: size.height,
),
],
),
),
],
));
}
}
class ImageShaderWidget extends StatelessWidget {
#override
Widget build(BuildContext context) => Container(
child: FutureBuilder<TextStyle>(
future: loadImage(
TextStyle(fontSize: 104.0, fontWeight: FontWeight.w900)),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return Text(
"Penumbra",
style: snapshot.data,
);
}
},
),
);
Future<TextStyle> loadImage(TextStyle textStyle) async {
final imageBytes = await rootBundle.load('../assets/images/background.jpg');
ui.Image img = await decodeImageFromList(imageBytes.buffer.asUint8List());
Float64List matrix4 = new Matrix4.identity().storage;
return textStyle.copyWith(
foreground: Paint()
..shader =
ImageShader(img, TileMode.mirror, TileMode.mirror, matrix4));
}
}

How to return flip cards to their original position from a widget in another dart file?

I'm relatively new to Flutter and have tried to find similar postings to help me but haven't had any luck in getting them to work for me unfortunately. I have an Android Studio program that's basically a game which involves a grid of flip cards. I have the flip cards in one dart file and the app bar in another. I have an iconbutton on the app bar which currently reduces the point count to zero, but I would also like for it to flip all of the flip cards back to their original positions when pressed. I have a global variable called resetBool that I've been trying to use, something like if resetBool == true then toggleCard() maybe. I think I might need to use a key but am having trouble implementing one properly.
Here is the code in the file which contains my appbar:
import 'package:flip_card/flip_card.dart';
import 'package:flutter/material.dart';
import 'gridone.dart' as gridone;
import 'globalVariables.dart';
import 'statenames.dart';
int count;
StateNames stateObject = new StateNames();
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home>with SingleTickerProviderStateMixin {
TabController controller;
#override
void initState() {
controller = new TabController(length: 1, vsync: this);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
void changeCount() {
setState(() {
counter += 1;
});
}
void decreaseCount() {
setState(() {
counter -= 1;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title:new Text("License plate game"),
backgroundColor: Colors.greenAccent,
actions: <Widget>[
IconButton(
icon: Icon(
Icons.autorenew,
color: Colors.white,
),
onPressed: () {
setState(() {
counter = 0;
resetBool = true;
});
},
),
Center(
child: Container(
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Text('points: $counter', textAlign: TextAlign.center, style: TextStyle(fontSize: 15),
)
),
),
],
bottom: new TabBar(
controller: controller,
indicatorWeight: 5.0,
indicatorColor: Colors.green,
tabs: <Widget> [
new Tab(icon: new Icon(Icons.image),),
],
),
),
body: new TabBarView(
controller: controller,
children: <Widget>[
new gridone.GridOne(changeCount, decreaseCount),
],
)
);
}
}
And here is the code in the file which contains my flip cards:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flip_card/flip_card.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'statenames.dart';
import 'globalVariables.dart';
import 'Home.dart';
import 'gridtwo.dart' as gridTwo;
StateNames stateObject = new StateNames();
Home homeObject = new Home();
class GridOne extends StatefulWidget {
final Function updateCounter;
final Function decreaseCount;
GridOne(this.updateCounter, this.decreaseCount);
#override
_GridOneState createState() => _GridOneState();
}
class _GridOneState extends State<GridOne>
with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
int points = 0;
#override
Widget build(BuildContext context) {
super.build(context);
return new Scaffold(
body: new Column(
children: <Widget> [
new Expanded(
child: GridView.count(
crossAxisCount: 5,
children: List.generate(52, (index){
return Card(
elevation: 0.0,
margin: EdgeInsets.only(left: 3.0, right: 3.0, top: 9.0, bottom: 0.0),
color: Color(0x00000000),
child: FlipCard(
direction: FlipDirection.HORIZONTAL,
speed: 1000,
//(resetBool == true) ? cardKey.currentState.toggleCard() : null,
onFlipDone: (status) {
setState(() {
(status)
? widget.decreaseCount()
: widget.updateCounter();
});
if (counter == 25) {
Fluttertoast.showToast(
msg: "You've got 25 states! Wow!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM_LEFT,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
};
print(counter);
},
front: Container(
decoration: BoxDecoration(
color: Color(0xFF006666),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
FittedBox(fit:BoxFit.fitWidth,
child: Text(stateObject.stateNames[index], style: TextStyle(fontFamily: 'Architects Daughter', color: Colors.white), )
//Theme.of(context).textTheme.headline
),
Text('',
style: Theme.of(context).textTheme.body1),
],
),
),
back: Container(
decoration: BoxDecoration(
color: Color(0xFF006666),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(image: AssetImage(stateObject.licensePlatePaths[index])),
//Text('',
//style: Theme.of(context).textTheme.body1),
],
),
),
),
);
})
)
)
]
),
);
}
}
The solution is to use currentState.toggleCard(); for the cards that are facing Back when the IconButton is clicked.
Basically, what I did is I gave keys to each card at initState method.
List<GlobalKey<FlipCardState>> cardKeys = [];
#override
void initState() {
List.generate(52, (index) {
cardKeys.add(GlobalKey<FlipCardState>());
});
super.initState();
}
Don't forget to put the key to widget
FlipCard(key: cardKeys[index], ... )
Then, call resetCards method below when the button is clicked. If the card is facing back then toggle logic.
void resetCards() {
cardKeys.forEach((element) {
if (!element.currentState.isFront) {
element.currentState.toggleCard();
}
});
setState(() {});
}
You need to call a method on the parent widget, that would be triggered in the child widget. For that, please check this stackoverflow link
Full working code:
import 'package:flutter/material.dart';
import 'package:flip_card/flip_card.dart';
import 'package:fluttertoast/fluttertoast.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: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
// This makes the visual density adapt to the platform that you run
// the app on. For desktop platforms, the controls will be smaller and
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
TabController controller;
int counter = 0;
final GridOneController myController = GridOneController();
#override
void initState() {
controller = new TabController(length: 1, vsync: this);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
void changeCount() {
setState(() {
counter += 1;
});
}
void decreaseCount() {
setState(() {
counter -= 1;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("License plate game"),
backgroundColor: Colors.greenAccent,
actions: <Widget>[
IconButton(
icon: Icon(
Icons.autorenew,
color: Colors.white,
),
onPressed: () {
setState(() {
counter = 0;
myController.resetCards();
});
},
),
Center(
child: Container(
padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
child: Text(
'points: $counter',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15),
)),
),
],
bottom: new TabBar(
controller: controller,
indicatorWeight: 5.0,
indicatorColor: Colors.green,
tabs: <Widget>[
new Tab(
icon: new Icon(Icons.image),
),
],
),
),
body: new TabBarView(
controller: controller,
children: <Widget>[
new GridOne(counter, myController),
],
));
}
}
class GridOneController {
void Function() resetCards;
}
class GridOne extends StatefulWidget {
int counter;
final GridOneController controller;
GridOne(this.counter, this.controller);
#override
_GridOneState createState() => _GridOneState(controller);
}
class _GridOneState extends State<GridOne> {
_GridOneState(GridOneController _controller) {
_controller.resetCards = resetCards;
}
int points = 0;
void increaseCounter() {
widget.counter += 1;
}
void decreaseCounter() {
widget.counter -= 1;
}
void resetCards() {
cardKeys.forEach((element) {
if (!element.currentState.isFront) {
element.currentState.toggleCard();
}
});
setState(() {});
}
List<GlobalKey<FlipCardState>> cardKeys = [];
#override
void initState() {
List.generate(52, (index) {
cardKeys.add(GlobalKey<FlipCardState>());
});
super.initState();
}
#override
Widget build(BuildContext context) {
print(cardKeys.length);
return new Scaffold(
body: new Column(children: <Widget>[
new Expanded(
child: GridView.count(
crossAxisCount: 5,
children: List.generate(52, (index) {
return Card(
elevation: 0.0,
margin: EdgeInsets.only(
left: 3.0, right: 3.0, top: 9.0, bottom: 0.0),
color: Color(0x00000000),
child: new FlipCard(
key: cardKeys[index],
direction: FlipDirection.HORIZONTAL,
speed: 1000,
onFlipDone: (status) {
setState(() {
(status) ? decreaseCounter() : increaseCounter();
});
if (widget.counter == 25) {
Fluttertoast.showToast(
msg: "You've got 25 states! Wow!",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM_LEFT,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
;
print(widget.counter);
},
front: Container(
decoration: BoxDecoration(
color: Color(0xFF006666),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
FittedBox(
fit: BoxFit.fitWidth,
child: Text(
'FRONT',
style: TextStyle(color: Colors.white),
)
//Theme.of(context).textTheme.headline
),
Text(
'',
),
],
),
),
back: Container(
decoration: BoxDecoration(
color: Color(0xFF006666),
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Text('BACK')],
),
),
),
);
})))
]),
);
}
}

How do I make it so that all filters don't change color when tapped on flutter

I'm trying to make a template for a filter that takes in one parameter (the tag name) and gets highlighted when tapped. But the problem with this is when one filter is tapped all of them change color because they all use the same boolean value. Sorry, I'm a beginner and I think I'm going about this the wrong way
class _HomeState extends State<Home> {
bool filterTap = true;
GestureDetector filterTemplate(String tag) {
return GestureDetector(
onTap: () {
setState(() {
filterTap = !filterTap;
});
},
child: Center(
child: Container(
margin: const EdgeInsets.only(right: 20.0),
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(4.0)),
color: filterTap ? Colors.grey : Colors.transparent,
),
child: Text(
tag,
style: TextStyle(
color: filterTap ? Colors.grey[900] : Colors.grey,
letterSpacing: 2.0,
),
),
),
),
);
}
first of all define a StructFilter class with its properties, For example here is an option:
class StructFilter {
StructFilter(this.tag,this.filterTap);
String tag;
bool filterTap;
}
Then collect all of your filter information into a list of StructFilter(i.e List<StructFilter> filterList).
For example you can try:
Listview(
children: filterList.map((item){
return filterTemplate(item);
}).toList();
)
GestureDetector filterTemplate(StructFilter structFilter) {
return GestureDetector(
onTap: () {
setState(() {
structFilter.filterTap = !structFilter.filterTap;
});
},
),
);
}
Use List or Map or List<YourClass> to maintain status of each button.
And try ChoiceChip,
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: Home()));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Map<String, bool> tagsList = {
"Tag1": false,
"Tag2": false,
"Tag3": false,
"Tag4": false,
};
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Row(
children: tagsList.entries.map((entry) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ChoiceChip(
label: Text(entry.key),
selected: entry.value,
onSelected: (value) {
setState(() {
tagsList[entry.key] = value;
});
},
),
);
}).toList(),
),
),
);
}
}

Flutter pass variable to SearchDelegate class gives error

I am a newbie to flutter, I am having a problem with passing the data to my search delegate class. The problem is that I have two tabs and I want to search within the active tab. So I am trying to send a variable that tells which tab is it and which table to look for value.
Here is what my code looks like:
class HomePage extends StatefulWidget {
static final String routeName = 'home';
#override
State<StatefulWidget> createState() {
return new _HomePageState();
}
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
var activeTab = "activity";
var _authToken, _id, _name, _emails, _userImage;
#override
void initState() {
super.initState();
tabController = TabController(vsync: this, length: 2)..addListener(() {
setState(() {
switch (tabController.index) {
case 0:
activeTab = "activity";
break;
case 1:
activeTab = "subparticipants";
break;
}
});
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
// appBar: new AppBar(
// title: Text('Dashboard'),
// ),
body: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
labelColor: Color(0xFFFFFFFF),
indicatorSize: TabBarIndicatorSize.tab,
tabs: [
//Tab(icon: Icon(Icons.directions_car)),
Tab(
text: "Activity Zone",
),
Tab(
text: "Sub Participant",
)
],
controller: tabController,
),
title: Text(
'Dashboard',
style: new TextStyle(
color: const Color(0xFFFFFFFF),
fontSize: 20.0,
fontWeight: FontWeight.w600,
letterSpacing: 0.3,
),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch(activeTab));
},
)
],
),
body: TabBarView(
controller: tabController,
children: [
TabActivity(),
TabSubparticipant(),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
print(
'Current Index: $activeTab');
},
),
drawer: _buildDrawer(context),
),
),
);
}
}
class DataSearch extends SearchDelegate{
final String activeTab;
DataSearch(this.activeTab);
#override
List<Widget> buildActions(BuildContext context){
return [
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: (){
query=activeTab;
},
)
];
}
#override
Widget buildLeading(BuildContext context) => IconButton(
icon: Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
);
#override
Widget buildResults(BuildContext context) => Text('Result');
#override
Widget buildSuggestions(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Search by job id, asset name, client name $query',
style: new TextStyle(
color: Colors.black, fontWeight: FontWeight.bold, fontSize: 22.0),
),
);
}
}
When I try to get $activeTab and show it in query or somewhere else, It just gives out the error:
flutter: The following assertion was thrown building _SearchPage<dynamic>(dirty, dependencies:
flutter: [_LocalizationsScope-[GlobalKey#a02e3], _InheritedTheme], state: _SearchPageState<dynamic>#eceaa):
flutter: 'package:flutter/src/widgets/basic.dart': Failed assertion: line 6173 pos 15: 'child != null': is
I am a bit confused how should I pass value to it. I have seen some of similar questions but they are no help. Like this or this question. None of these have any of these errors. Can you please let me know what am I doing wrong. Whats the issue? Please help.
Well, For someone who dumb as me and is having the same problem as I am, Here is how you can fix the issue,
So I was not passing the correct value to Search delegate and was not picking it up properly. Here is the fixed part of code
class DataSearch extends SearchDelegate {
DataSearch({
#required this.activeTab,
});
final activeTab;
#override
Widget buildResults(BuildContext context) {
if (activeTab == "subparticipants") {
...... .
....
..

Resources