I need to change implement custom Icons for default button and drawer button for all pages in my project.
I know we have the option of using leading property, however, this only affects that certain page.
How can we change the default back button and open drawer button of AppBar in Flutter for the whole app?
Unfortunately, there is not a property called defaultBackButton or defaultDrawerButton.
So, in order to change these defaults in the whole app, we can create a CustomAppBar which and set Icons as we wish.
Please click here to see Demo on DartPad and test it yourself.
For a bit longer description, checkout my Medium story.
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
final Widget? leading;
final Widget? title;
final bool? centerTitle;
final bool automaticallyImplyLeading;
const CustomAppBar({
Key? key,
this.leading,
this.title,
this.centerTitle,
this.automaticallyImplyLeading = true,
}) : super(key: key);
#override
Widget build(BuildContext context) {
/// This part is copied from AppBar class
final ScaffoldState? scaffold = Scaffold.maybeOf(context);
final bool hasDrawer = scaffold?.hasDrawer ?? false;
final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context);
final bool canPop = parentRoute?.canPop ?? false;
Widget? leadingIcon = leading;
if (leadingIcon == null && automaticallyImplyLeading) {
if (hasDrawer) {
leadingIcon = IconButton(
icon: const Icon(Icons.mood_sharp, color: Colors.yellowAccent),
onPressed: () => Scaffold.of(context).openDrawer(),
);
} else {
if (canPop) {
leadingIcon = IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(
Icons.sentiment_dissatisfied_sharp,
color: Colors.red,
),
);
}
}
}
return AppBar(
leading: leadingIcon,
title: title,
centerTitle: centerTitle,
);
}
#override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}
Related
I want to bypass an Icon Widget to a custom widget and get the Icons codePoint value make some changes and return the new Icon Widget.
class NewCustomWidget extends StatefulWidget {
const NewCustomWidget({
Key? key,
this.mySize,
this.myIcon,
}) : super(key: key);
final double? mySize;
final Icon? myIcon;
#override
_NewCustomWidgetState createState() => _NewCustomWidgetState();
}
class _NewCustomWidgetState extends State<NewCustomWidget> {
#override
Widget build(BuildContext context) {
return Icon(
???? howto bypass the widget.myIcon's codePoint/IconData to the new Icon ????
color: Colors.black,
size: widget.mySize,
);
}
}
I tried to use the widget.myIcon.toString() but I get only the String "widget"
Icon takes IconData. You can do
return Icon(
widget.myIcon?.icon,
color: Colors.black,
size: widget.mySize,
);
I have used the mobile Spotify app on my device for the first time and I have noticed how the play/pause Button that is scrolling with the site, but to the top.
Now I am asking myself: How could I implement this in Flutter?
How could I make the Appbar become opaque from transparent with scrolling?
I have this special widget i build it on my own, hope this could help you
Note: give this widget ScrollController that connect to the listview
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:tvri/PORTRAIT/themes/my_themes.dart';
class SliverBar extends StatefulWidget with PreferredSizeWidget {
const SliverBar({
super.key,
required this.scrollController,
required this.title,
this.leading,
this.actionButton,
this.centerTitle = true,
this.titleSpacing = 0.0,
this.withLeading = true,
});
final ScrollController scrollController;
final dynamic title;
final Widget? leading;
final List<Widget>? actionButton;
final bool centerTitle;
final double titleSpacing;
final bool withLeading;
#override
State<SliverBar> createState() => _SliverBarState();
#override
Size get preferredSize => const Size.fromHeight(60);
}
class _SliverBarState extends State<SliverBar> {
double visibleCount = 0;
#override
void initState() {
super.initState();
widget.scrollController.addListener(scrollListener);
}
scrollListener() {
double maxHeight = Get.statusBarHeight;
double offset = widget.scrollController.offset;
if (offset < maxHeight) {
setState(() {
visibleCount = offset / maxHeight;
});
} else if (offset > maxHeight && visibleCount < 1.0) {
setState(() {
visibleCount = 1.0;
});
}
}
#override
Widget build(BuildContext context) {
return AppBar(
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // <-- SEE HERE
statusBarIconBrightness:
Brightness.light, //<-- For Android SEE HERE (dark icons)
statusBarBrightness:
Brightness.light, //<-- For iOS SEE HERE (dark icons)
),
automaticallyImplyLeading: false,
backgroundColor: MyThemes.colorBlue.withOpacity(visibleCount),
elevation: 0,
centerTitle: widget.centerTitle,
titleSpacing: widget.titleSpacing,
leading: widget.withLeading
? widget.leading ??
IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(Icons.chevron_left, size: 24),
)
: null,
title: widget.title is String
? Text(
widget.title,
style: const TextStyle(
color: MyThemes.colorWhite,
fontSize: 16,
),
)
: widget.title,
actions: widget.actionButton,
);
}
}
I am trying to change the colour of an icon so black so that it matches the rest of the text.
I use the following statement to determine which icon to use based on the theme:
class ChangeThemeButtonWidget extends StatelessWidget {
const ChangeThemeButtonWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Provider.of<ThemeProvider>(context).isDarkMode
? dark_mode_icon()
: Icons.light_mode),
onPressed: () {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(!provider.isDarkMode);
},
);
}
And
IconData dark_mode_icon() {
//return IconData(0xe37a, fontFamily: 'MaterialIcons');
IconData dark_mode_i = IconData(Icons.dark_mode, color: Colors.black);
return dark_mode_i;
}
My issue is that this returns the error "The argument type 'IconData' can't be assigned to the parameter type 'int'."
How can I edit the style of this icon so that it will change the color correctly?
Many thanks for the help
You are applying color on wrong place. IconData is just widget that describes Icon based on font data. It has nothing to do with color. You have to put those IconData into Icon widget and change color there.
class ChangeThemeButtonWidget extends StatelessWidget {
const ChangeThemeButtonWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Provider.of<ThemeProvider>(context).isDarkMode
? Icons.dark_mode
: Icons.light_mode,
color: #HERE
),
onPressed: () {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(!provider.isDarkMode);
},
);
}
Simply use this code:
IconButton(
onPressed: () {},
color: Colors.blue,
iconSize: 100,
icon: Icon(
Icons.train,
),
)
That is how you can apply color to the iconbutton.
Icons.darkmode is the icon data. IconData() will take an integer so yiu have to write IconData(Icons.darkmode.codePoint)
I'm using the flutter url_launcher https://pub.dev/packages/url_launcher package to open urls when i click some button.
With the new Link widget im now able to open a web page on the same tab but i cant add mouse pointer when user is hovering the button
import 'package:bianca/UI/botao_azul.dart';
import 'package:url_launcher/link.dart';
import 'package:flutter/material.dart';
String link = "https://www.google.com";
class MesmaAba extends StatelessWidget {
final double tamanho;
final String conteudo;
MesmaAba({this.tamanho, this.conteudo});
#override
Widget build(BuildContext context) {
return Link(
uri: Uri.parse(link),
builder: (BuildContext context, FollowLink followLink) => BotaoAzul(
conteudo: conteudo,
tamanho: tamanho,
funcao: followLink
),
);
}
}
BotaoAzul class:
import 'package:flutter/material.dart';
class BotaoAzul extends StatelessWidget {
final String conteudo;
final double tamanho;
final Function funcao;
BotaoAzul({this.conteudo, this.tamanho,this.funcao});
#override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FlatButton(
onPressed: funcao,
child: Text(conteudo,
style: TextStyle(
fontSize: tamanho,
color: Colors.white,
fontWeight: FontWeight.bold))),
),
decoration: BoxDecoration(
color: Colors.blue[900], borderRadius: BorderRadius.circular(20.0)),
);
}
}
I can already open urls with botaoAzul button on another tab using this function (and without the Link widget, the mouse changes on hovering the button)
import 'package:url_launcher/url_launcher.dart';
void launchLink(String link) async {
await launch(
link,
);
}
But i need to open the url on the same tab.
I've already tried all implementations of this other question without success:
https://stackoverflow.com/questions/56211844/flutter-web-mouse-hover-change-cursor-to-pointer
As I know latest version of flutter web supports hand cursor for InkWell widget automatically. Below simple class:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
/// Provides an anchor link to web URL.
class HoveredWebAnchor extends StatefulWidget {
HoveredWebAnchor(
{Key key,
#required this.label,
#required this.url,
this.underlined = true})
: assert(label != null),
assert(url != null),
assert(underlined != null),
super(key: key);
/// The label of anchor
final String label;
/// The web URL to open when anchor clicked
final String url;
/// Identifies if anchor label will be underlined.
final bool underlined;
#override
_HoveredWebAnchorState createState() => _HoveredWebAnchorState();
}
class _HoveredWebAnchorState extends State<HoveredWebAnchor> {
/// Current text style
TextStyle _textStyle;
#override
Widget build(BuildContext context) {
return InkWell(
hoverColor: Colors.transparent,
child: Text(
widget.label,
style: _textStyle,
),
onHover: (hovered) {
setState(() {
if (hovered) {
_textStyle = TextStyle(color: Theme.of(context).accentColor);
if (widget.underlined) {
_textStyle = _textStyle.copyWith(
decoration: TextDecoration.underline,
);
}
} else {
_textStyle = null;
}
});
},
onTap: () {
launch(widget.url, forceWebView: true);
},
);
}
}
Using:
HoveredWebAnchor(
label: 'Open Google',
url: 'http://www.google.com',
),
I have improved suggestion of #BambinoUA to sound null safety and some minor changes so I decided to share it with y'all
class HoveredWebAnchor extends StatefulWidget {
const HoveredWebAnchor(
this.label, {
Key? key,
required this.style,
this.maxLines,
required this.onTap,
}) : super(key: key);
final String label;
final TextStyle? style;
final int? maxLines;
final VoidCallback onTap;
#override
_HoveredWebAnchorState createState() => _HoveredWebAnchorState();
}
class _HoveredWebAnchorState extends State<HoveredWebAnchor> {
TextStyle? _textStyle;
#override
void initState() {
_textStyle = widget.style;
super.initState();
}
#override
Widget build(BuildContext context) {
return InkWell(
hoverColor: Colors.transparent,
onHover: (hovered) {
setState(() {
if (hovered) {
_textStyle = _textStyle?.copyWith(
decoration: TextDecoration.underline,
);
} else {
_textStyle = _textStyle?.copyWith(
decoration: widget.style?.decoration,
);
}
});
},
onTap: widget.onTap,
child: Text(
widget.label,
style: _textStyle,
maxLines: widget.maxLines,
),
);
}
}
The way to change your mouse cursor whilst keeping the behavior of the Link Widget the same would be to wrap the Link Widget in a MouseRegion
MouseRegion(
cursor: SystemMouseCursors.click,
child: Link(
uri: Uri.parse(link),
builder: (BuildContext context, FollowLink followLink) =>
BotaoAzul(
conteudo: conteudo,
tamanho: tamanho,
funcao: followLink
),
),
)
From the Link widget revision 2 document:
The Link widget doesn’t provide any mouse cursor, and fully relies on the user to do their own mouse cursor. In many cases, users will be using a button, which already shows the correct mouse cursor. In other cases, the user can wrap the Link (or the child of the Link) in a mouse region and give it a cursor.
found something last night that solves the problem:
Instead of using url_launcher Link, i'm now importing the html package
import 'dart:html' as html;
String link = "https://www.google.com";
.....
void openPage(){
html.window.location.assign(link);
}
...... (widget build method)
BotaoAzul(
conteudo: "Hey",
tamanho: 30,
funcao: openPage
),
It now opens the link on the same tab and i can return to my flutter app from the chrome back button
I working creating a favorite page. For each Product Page, I place on app bar a favorite icon that suppose to change and add the specific product to the favorites of the user.
I am failing to change the state of the icon after pressing it.
class FoodDetail extends StatefulWidget {
#override
_FoodDetail createState()=> _FoodDetail();
const FoodDetail({Key key}) : super(key: key);
}
class _FoodDetail extends State<FoodDetail>{
#override
Widget build(BuildContext context) {
FoodNotifier foodNotifier = Provider.of<FoodNotifier>(context);
_onFoodDeleted(Food food) {
Navigator.pop(context);
foodNotifier.deleteFood(food);
}
final _saved = Set<BuildContext>();
final alreadySaved = _saved.contains(context);
return Scaffold(
appBar: AppBar(
title: Text(foodNotifier.currentFood.name),
actions: <Widget>[
// action button
new IconButton(
icon: alreadySaved ? Icon(Icons.star) : Icon(Icons.star_border),
color: alreadySaved ? Colors.yellow[500] : null,
onPressed: (){
setState(() {
if (alreadySaved) {
_saved.remove(context);
} else {
_saved.add(context);
}
});}
Your states doesn't change because you're putting them inside the build method which always reinitialize them.
Put your states _saved, alreadySaved outside the build method.
final _saved = Set<BuildContext>();
final alreadySaved = _saved.contains(context);
#override
Widget build(BuildContext context) {
}