Related
i have a widget with an AppBar:
class CustomersView extends StatefulWidget {
#override
State<CustomersView> createState() => _CustomersViewState();
}
class _CustomersViewState extends State<CustomersView> {
#override
Widget build(BuildContext context) {
//final controller = Get.put(EServicesController());
return Scaffold(
appBar: AppBar(
toolbarHeight: 60,
backgroundColor: Colors.white,
title: Text(
"Customers".tr,
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 20,
fontWeight: FontWeight.w600),
),
actions: [
SearchButtonWidget(),
SettingsButtonWidget(),
],
centerTitle: false,
elevation: 0,
automaticallyImplyLeading: false,
leadingWidth: 15,
// leading: new IconButton(
// icon: new Icon(Icons.arrow_back_ios, color: Color(0xff3498DB)),
// onPressed: () => {Get.back()},
// ),
),
body: RefreshIndicator(
onRefresh: () async {
// Get.find<LaravelApiClient>().forceRefresh();
// await controller.refreshNotifications(showMessage: true);
// Get.find<LaravelApiClient>().unForceRefresh();
},
child: ListView(
primary: true,
children: <Widget>[
mainHeader(),
SizedBox(
height: 10,
),
CustomersCategoriesBuilder(current: current),
],
),
),
//floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
bottomNavigationBar: current == 0 ? SizedBox() : MessageCustomersButton(),
);
}
}
And i have another customized AppBar in another widget :
class MessageCustomersAppBar extends StatelessWidget with PreferredSizeWidget {
final bool isSecondStyleAppBar;
const MessageCustomersAppBar(this.isSecondStyleAppBar, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppBar(
toolbarHeight: 60,
backgroundColor: Colors.white,
title: Text(
"Customers".tr,
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 20,
fontWeight: FontWeight.w600),
),
actions: [
// SearchButtonWidget(),
// SettingsButtonWidget(),
],
centerTitle: false,
elevation: 0,
automaticallyImplyLeading: false,
leadingWidth: 15,
leading: new IconButton(
icon: new Icon(Icons.arrow_back_ios, color: Color(0xff3498DB)),
onPressed: () => {Get.back()},
),
);
}
#override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
In the initial widget, i have a bottomNavigationBar that has a button MessageCustomersButton() and in the second CustomAppBar widget i have a leading
I want to switch AppBar to the CustomAppBar when this button is pressed ( i am using Getx ) & switch back to the Original AppBar when the leading button is pressed.
I have tried managing state myself but it looks like i am getting it wrong for the past days now.
Please i need help. Thank you!
You can change the AppBar in GetX using the OBX method. Below is the code for implementing those things.
1.View File
class CustomersView extends StatefulWidget {
#override
State<CustomersView> createState() => _CustomersViewState();
}
class _CustomersViewState extends State<CustomersView> {
#override
Widget build(BuildContext context) {
final controller = Get.put(AppBarController());
return Obx(
() => Scaffold(
appBar: controller.isChangeAppBar.value
? MessageCustomersAppBar()
: AppBar(
toolbarHeight: 60,
backgroundColor: Colors.white,
title: Text(
"Customers".tr,
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 20,
fontWeight: FontWeight.w600),
),
actions: [
SearchButtonWidget(),
SettingsButtonWidget(),
],
centerTitle: false,
elevation: 0,
automaticallyImplyLeading: false,
leadingWidth: 15,
),
body: RefreshIndicator(
onRefresh: () async {},
child: ListView(
primary: true,
children: <Widget>[
mainHeader(),
SizedBox(
height: 10,
),
CustomersCategoriesBuilder(current: current),
],
),
),
bottomNavigationBar:
current == 0 ? SizedBox() : MessageCustomersButton(),
//here's the ontap method for the button
// () {
// controller.isChangeAppBar.value = !controller.isChangeAppBar.value;
// }
),
);
}
}
Your custom AppBar file remains the same.
GetX controller File:
class AppBarController extends GetxController {
Rx<bool> isChangeAppBar = false.obs;
}
Im trying to make it so when you press search it creates a listtile. It works but for it to work I have to click the button and then rebuild the app for it to appear. I was looking at some other posts but I could not find anything that worked. The main parts to look at is I have a function that adds a listtile. I have a button with an on press to create the tile. And I have the children of container at the bottom as the list of created listtiles.
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Widget> _listOfWidgets = [];
#override
Widget build(BuildContext context) {
_addItemToList() {
List<Widget> tempList =
_listOfWidgets; // defining a new temporary list which will be equal to our other list
tempList.add(ListTile(
key: UniqueKey(),
leading: Icon(Icons.list),
trailing: FlatButton(
onPressed: () async {},
//Download Link
child: Text(
"Download",
style: TextStyle(color: Colors.green, fontSize: 15),
),
),
title: Text("")));
this.setState(() {
_listOfWidgets =
tempList; // this will trigger a rebuild of the ENTIRE widget, therefore adding our new item to the list!
});
}
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: currentTheme.currentTheme(),
home: Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
setState(() {
currentTheme.switchTheme();
});
},
icon: Icon(Icons.wb_sunny),
),
IconButton(
onPressed: () async {
await FirebaseAuth.instance.signOut();
},
icon: Icon(Icons.exit_to_app),
),
],
backgroundColor: Colors.blue,
title: Text("Home"),
),
body: ListView(
children: [
ListTile(
leading: SizedBox(
width: 300,
child: TextField(
controller: search,
decoration: InputDecoration(
labelText: "Enter Manga Name",
),
),
),
trailing: ElevatedButton(
onPressed: () async {
_addItemToList();
},
child: Text("Search")),
),
Container(
margin: EdgeInsets.all(15),
width: 100,
height: 515,
color: Colors.black12,
child: ListView(
children: _listOfWidgets,
))
],
)));
}
}
try add below code
if you update status you need setState()
A better way to state management is to use a BLoC or Provider package.
...
onPressed: () {
setState(() {
_addItemToList();
});
},
...
Figured it out after a bit of tinkering. Fix for me was to add key: UniqueKey(), to my ListView. I had keys added to my ListTiles instead of the actual ListView.
onPressed: () {
setState(() {
_addItemToList();
});
},
The Problem Solution is :
List<Widget> tempList = <Widget>[];
_addItemToList() {
tempList.addAll(
_listOfWidgets); // defining a new temporary list which will be equal to our other list
tempList.add(ListTile(
key: UniqueKey(),
leading: Icon(Icons.list),
trailing: FlatButton(
onPressed: () async {},
//Download Link
child: Text(
"Download",
style: TextStyle(color: Colors.green, fontSize: 15),
),
),
title: Text("")));
this.setState(() {
_listOfWidgets =
tempList; // this will trigger a rebuild of the ENTIRE widget, therefore adding our new item to the list!
});
}
i can change my background color and app bar in home just fine, but when i click the search icon which uses search delegate it all back to white, how do i change the color? just to make it clear, so before the user clicked the search icon the background and app bar was black but when they clicked it it turned to white, how do i change it?
here is the search code :
import 'package:flutter/material.dart';
import 'package:movie_app_3/model/movie_response.dart';
import 'package:movie_app_3/screens/movie_detail_screen/movie_detail_screen.dart';
import '../model/movie.dart';
import '../repository/repository.dart';
class DataSearch extends SearchDelegate {
// void initState() {
// searchBloc..getSearch(query);
// }
final movieRepo = MovieRepository();
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () => query = '',
)
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
onPressed: () => close(context, null),
);
}
#override
Widget buildResults(BuildContext context) {
return Container();
}
#override
Widget buildSuggestions(BuildContext context) {
if (query.isEmpty) return Container();
return FutureBuilder<MovieResponse>(
future: movieRepo.getSearch(query),
builder: (BuildContext context, AsyncSnapshot<MovieResponse> snapshot) {
if (snapshot.hasData) {
if (snapshot.data.error != null && snapshot.data.error.length > 0) {
return _buildErrorWidget(snapshot.data.error);
}
return _buildHomeWidget(snapshot.data);
} else if (snapshot.hasError) {
return _buildErrorWidget(snapshot.error);
} else {
return _buildLoadingWidget();
}
},
);
}
Widget _buildHomeWidget(MovieResponse data) {
List<Movie> movies = data.movies;
return ListView.builder(
itemCount: movies.length,
itemBuilder: (context, index) {
return ListTile(
leading: FadeInImage(
image: movies[index].poster == null
? AssetImage('assets/images/no-image.jpg')
: NetworkImage("https://image.tmdb.org/t/p/w200/" +
movies[index].poster),
placeholder: AssetImage('assets/images/no-image.jpg'),
width: 50.0,
fit: BoxFit.contain),
title: Text(
movies[index].title,
style: TextStyle(fontFamily: 'Poppins'),
),
subtitle: Text(
movies[index].overview,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontFamily: 'Raleway'),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MovieDetailScreen(movie: movies[index]),
),
);
},
);
},
);
}
Widget _buildLoadingWidget() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 25.0,
width: 25.0,
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(Colors.black),
strokeWidth: 4.0,
),
)
],
));
}
Widget _buildErrorWidget(String error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Error occured: $error"),
],
));
}
// #override
// Widget buildSuggestions(BuildContext context) {
// final suggestedList = (query.isEmpty) ?
// recentMovies :
// movies.where((movie) => movie.toLowerCase().contains(query.toLowerCase())).toList();
// return ListView.builder(
// itemCount: suggestedList.length,
// itemBuilder: (context, i) {
// return ListTile(
// leading: Icon(Icons.movie),
// title: Text(suggestedList[i]),
// onTap: () {},
// );
// },
// );
// }
}
here is the home code :
import 'package:flutter/material.dart';
import 'package:movie_app_3/widget/drawer.dart';
import 'package:movie_app_3/screens/home_screen/widget/home_screen1.dart';
import 'package:movie_app_3/screens/home_screen/widget/home_screen2.dart';
import 'package:movie_app_3/widget/search.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 2);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black,
Color(0xff112339),
Colors.black,
],
),
),
child: DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
elevation: 0,
title: Text(
'Moviez',
style: TextStyle(
fontSize: 24,
color: Colors.white,
fontFamily: 'Poppins',
),
),
backgroundColor: Colors.transparent,
centerTitle: true,
actions: [
Padding(
padding: EdgeInsets.only(right: 20),
child: IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch());
},
),
),
],
bottom: TabBar(
controller: _tabController,
indicatorColor: Colors.white,
indicatorSize: TabBarIndicatorSize.tab,
indicatorWeight: 2.0,
tabs: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'Discover',
style: TextStyle(fontSize: 16, fontFamily: 'Raleway'),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'Genres',
style: TextStyle(fontSize: 16, fontFamily: 'Raleway'),
),
),
],
),
),
drawer: MyDrawer(),
body: TabBarView(
controller: _tabController,
children: <Widget>[
FirstTab(),
SecondTab(),
],
),
),
),
);
}
}
For customizing the Search Delegate, you have to override a method called appBarTheme and then set your custom theme on that.
** NOTE: When you override appBarTheme of SearchDelegate you have to customize evrything related to SearchBar yourself. Just like the code below. **
Do this to change the AppBar Color:
#override
ThemeData appBarTheme(BuildContext context) {
return ThemeData(
appBarTheme: const AppBarTheme(
color: MyColors.mainColor, // affects AppBar's background color
hintColor: Colors.grey, // affects the initial 'Search' text
textTheme: const TextTheme(
headline6: TextStyle( // headline 6 affects the query text
color: Colors.white,
fontSize: 16.0,
fontWeight: FontWeight.bold)),
),
);
}
And for changing the background color of suggestions:
#override
Widget buildSuggestions(BuildContext context) {
return Container(
color: Colors.black,
...
);
}
Similarly do this for results:
#override
Widget buildResults(BuildContext context) {
return Container(
color: Colors.black,
...
);
}
Hope this helps.
Add this to your "DataSearch" class
class _SearchDelegate extends SearchDelegate {
#override
ThemeData appBarTheme(BuildContext context) {
return Theme.of(context).copyWith(
scaffoldBackgroundColor: Colors.green,
);
}
If you already set your MaterialApp theme you can simply use Theme.of(context).copywith to remain body theme. Then you can override appBarTheme to change desired color/styles.
#override
ThemeData appBarTheme(BuildContext context) {
return Theme.of(context).copyWith(
//scaffoldBackgroundColor: , to change scaffold color
appBarTheme: const AppBarTheme( //to change appbar
color: Colors.black,
//titleTextStyle: , to change title text
//toolbarTextStyle: , to change toolbar text style
),
);
I'm trying to build a collapse view after clicking an IconButton on my AppBar widget, I used ExpansionTile but nothing happens after I clicked the IconButton.
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
ExpansionTile(
title: Text(
"Settings",
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold
),
),
);
},
icon: Icon(Icons.settings),
),
],
),
Did I write the code right, or should I consider refactoring it. Thanks in advance!
Yes, you need to refactor your code because you cannot insert a widget into the widget tree this way directly from a function. I'm not sure of what you are trying to do, so I made two assumptions (1) You are trying to show a Expansion Tile in the app bar or (2) You want to show a Popup menu. Please see my code below to understand how you can achieve both.
import 'package:flutter/material.dart';
final Color darkBlue = const 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),
title: 'Welcome to Flutter',
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Widget myWidget = Container(
child: const Text("Flutter"),
);
String myText = 'Hello, World!';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: myWidget, actions: [
IconButton(
onPressed: () async {
print(context);
showMenu(
context: context,
position: const RelativeRect.fromLTRB(110.0, 80.0, 0.0, 0.0),
items: ["One", "Two", "Three", "Four"]
.map(
(value) => PopupMenuItem<String>(
child: Text(value),
value: value,
),
)
.toList(),
elevation: 8.0,
);
},
icon: Icon(Icons.settings),
),
PopupMenuButton<int>(
onSelected: (selected) {
setState(
() {
myText = "You selected the menu number $selected";
},
);
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<int>>[
const PopupMenuItem<int>(
value: 1,
child: Text('First Item'),
),
const PopupMenuItem<int>(
value: 2,
child: Text('Second Item'),
),
const PopupMenuItem<int>(
value: 3,
child: Text('Thrid Item'),
),
const PopupMenuItem<int>(
value: 4,
child: Text('Fourth Item'),
),
],
)
]),
body: Center(
child: Text(myText, style: Theme.of(context).textTheme.headline4),
),
);
}
}
I am trying to create a reusable appBar in my flutter app. The right bar button of the appbar should be controlled from main UI where it is added. I am able to create appBar and use it but I am not able to change the text color of the button on the appbar. Following is my code for creating appBar:
class SocialAppBar extends StatefulWidget implements PreferredSizeWidget {
AppBarConfig appBarConfig;
bool isEnabled = false;
VoidCallback rightButtonClickCallback;
SocialAppBar({#required this.appBarConfig, #required this.rightButtonClickCallback});
#override
State<StatefulWidget> createState() {
return SocialAppBarState();
}
#override
Size get preferredSize => new Size.fromHeight(kToolbarHeight);
}
class SocialAppBarState extends State<SocialAppBar> {
#override
Widget build(BuildContext context) {
return getAppBarWithProfilePic();
}
Widget getAppBarWithProfilePic() {
return AppBar(
brightness: Brightness.light,
backgroundColor: Colors.white,
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
key: const Key("backButton"),
onPressed: () {
Navigator.pop(context);
}),
iconTheme: const IconThemeData(
color: Colors.black54, //change your color here
),
titleSpacing: 0.0,
title: Row(
children: <Widget>[
buildAvatar(),
const SizedBox(
width: 15,
),
Text(widget.appBarConfig.fullName,
style: TextStyle(color: AppColor.appbarTitleSecondaryColor, fontWeight: FontWeight.w400))
],
),
actions: <Widget>[
Container(
alignment: Alignment.centerRight,
padding: const EdgeInsets.only(left: 20, right: 20),
child: InkWell(
child: AutoSizeText(
AppLocalizations.of(context).translate(GlobalString.labelNext),
style: TextStyle(color: widget.isEnabled ? AppColor.blue : AppColor.greyMediumDark, fontSize: 16),
textAlign: TextAlign.center,
),
onTap: widget.rightButtonClickCallback,
))
],
);
}
setNextButtonColor(){
setState(() {
});
}
}
I am using the above appBar like following in my screen:
void initState() {
super.initState();
appBar = SocialAppBar(appBarConfig: appBarConfig, rightButtonClickCallback: nextButtonClick);
//Next button on app bar should be enabled when following textController has any text
_textController.addListener((){
if (_textController.text.length > 0){
appBar.isEnabled = true;
}else {
appBar.isEnabled = false;
}
});
}
#override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _createPostBloc,
builder: (context, state) {
if (state is CreatePostNextState) {}
return Scaffold(
appBar: this.appBar,
key: _scaffoldKey,
backgroundColor: Colors.white,
body: buildPageView(),
);
},
);
}
I am able to set the Next button enable/disable with the above code but unable to change the color from Gray to Blue.
Regards
reusable AppBar:
Widget appBar(String text, IconButton iconButton) {
return AppBar(
title: Text(
text,
style: AppTheme.screenTitleStyle(),
),
centerTitle: true,
leading: IconButton(icon: iconButton, onPressed: () {}),
backgroundColor: AppTheme.mainThemeColor(),
brightness: Brightness.dark,
);
}
Use this appBar in Activity like this :
appBar: appBar(
"Change Password",
IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.of(context).pop();
},
),
),
Simple fix:
_textController.addListener((){
setState(() {
if (_textController.text.length > 0){
appBar.isEnabled = true;
}else {
appBar.isEnabled = false;
}
});
});