How to change value of variable in statefull widget from another widget - flutter

I have a variable inside a statefull widget which contains a string value. I called a widget from another dart file. I need to change the value of the variable in statefull widget from this widget. I have tries valuelistanablebuilder but it is only listen to value when function called inside that dart file. Please tell me a way and example code on how to do it.
import 'package:flutter/material.dart';
import 'package:messaging_service/components/app_bar.dart';
import 'package:messaging_service/components/home_pages/all_messages.dart';
import 'package:messaging_service/components/home_pages/stories.dart';
import 'package:messaging_service/components/search_bar.dart';
import 'package:messaging_service/components/strings.dart';
import 'package:messaging_service/components/style.dart';
class HomeMobile extends StatefulWidget {
const HomeMobile({Key? key}) : super(key: key);
#override
_HomeMobileState createState() => _HomeMobileState();
}
class _HomeMobileState extends State<HomeMobile> {
var currentPage = 'all';
TextEditingController searchChatController = TextEditingController();
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: lightColor,
appBar: AppBarHomeMobile(context),
body: SingleChildScrollView(
child: Column(
children: [
AppBarHomeExtend(),
const SizedBox(
height: 10,
),
//To Call a Widget
],
),
),
);
}
}
In this AppBarHomeExtend() has some buttons..
Widget AppBarHomeExtend() {
return Container(
height: 80,
decoration: BoxDecoration(
color: lightColor,
boxShadow: [
BoxShadow(color: darkColor, blurRadius: 5),
],
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(35), bottomRight: Radius.circular(35))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
HRButtons('All Messages', () {}),
HRButtons('Groups', () { }),
HRButtons('Stories', () {}),
HRButtons('Calls', () {}),
],
),
);
}
When called these buttons I need to change the value of variable currentPage from that statefull widget.

First, turn your AppBarHomeExtend into a proper widget which takes a callback function as argument:
import 'package:flutter/material.dart';
class ExtendedAppBar extends StatelessWidget {
final void Function(String) setPage;
const ExtendedAppBar({Key? key, required this.setPage}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 80,
decoration: BoxDecoration(
color: Colors.blue.shade50,
boxShadow: [
BoxShadow(color: Colors.blue.shade900, blurRadius: 5),
],
borderRadius: const BorderRadius.only(bottomLeft: Radius.circular(35), bottomRight: Radius.circular(35))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
HRButtons('All Messages', () => setPage('All Messages')),
HRButtons('Groups', () => setPage('Groups')),
HRButtons('Stories', () => setPage('Stories')),
HRButtons('Calls', () => setPage('Calls')),
],
),
);
}
}
Then in your _HomeMobileState class, use this:
ExtendedAppBar(
setPage: (String value) {
setState(() {
currentPage = value;
});
},
),

you better need to use a state management to get a better solution . check this package
floatingActionButton: FloatingActionButton(
key: const Key('increment_floatingActionButton'),
/// Calls `context.read` instead of `context.watch` so that it does not rebuild
/// when [Counter] changes.
onPressed: () => context.read<Counter>().increment(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
class Count extends StatelessWidget {
const Count({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text(
/// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
'${context.watch<Counter>().count}',
key: const Key('counterState'),
style: Theme.of(context).textTheme.headline4);
}
}

Related

The context you are using comes from the widget above the BlocProvider. I use Dialog

Faced a problem when adding Bloc. I use Counter which is in Dialog and do everything through Block but for some reason I got this error (see below). I did the same before and there was no error. I do not fully understand what the error is connected with and how to solve it correctly. I have a HomePage class in which I declare Bloc and in which the HomeBody class is nested, and in this class there is a button for opening Dialog (FilterDialog) and in this Dialog I have a Counter that I did through Bloc. I will be grateful for help.
home page
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<CounterCubit>(
create: (context) => CounterCubit(),
child: Scaffold(
extendBodyBehindAppBar: true,
appBar: LogoAppBar(
buttonIcon: SvgPicture.asset(constants.Assets.burgerMenu)),
body: const HomeBody(),
),
);
}
}
home body
class HomeBody extends StatelessWidget {
const HomeBody({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Container(
width: size.width,
height: size.height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/background/main_background.png'),
fit: BoxFit.cover,
),
),
child: _child(context, size),
);
}
Widget _child(context, Size size) => Padding(
padding: const EdgeInsets.only(top: 121, right: 24),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
return const FilterDialog();
},
);
},
child: Container(
height: 40,
width: 50,
decoration: const BoxDecoration(
color: Colors.amber,
),
alignment: Alignment.center,
child: const Text('Dialog'),
),
),
),
);
}
FilterDialog
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Dialog(
insetPadding: const EdgeInsets.only(top: 100, left: 24, right: 24),
backgroundColor: Colors.transparent,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(24))),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
color: constants.Colors.greyDark,
borderRadius: BorderRadius.all(Radius.circular(24)),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(21, 38, 21, 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PriceCounter(title: 'From'),
]
price counter
class PriceCounter extends StatelessWidget {
final String title;
const PriceCounter({Key? key, required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
final CounterCubit cubit = BlocProvider.of<CounterCubit>(context);
return Column(
children: [
BlocBuilder<CounterCubit, CounterState>(
builder: (context, state) => InputField(
price: state.countValue.toString(),
textStyle: constants.Styles.normalBookTextStyleWhite),
),
Row(
children: [
IconButton(
onPressed: () => cubit.increment(),
icon: SvgPicture.asset(constants.Assets.plus),
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
Text('Test', style: constants.Styles.smallLtStdTextStyleWhite),
IconButton(
onPressed: () => cubit.decrement(),
icon: SvgPicture.asset(constants.Assets.minus),
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
],
)
],
);
}
}
counter state
class CounterState {
final double countValue;
const CounterState({required this.countValue});
}
counter cubit
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(const CounterState(countValue: 0.13));
void increment() => emit(CounterState(countValue: state.countValue + 0.1));
void decrement() => emit(CounterState(countValue: state.countValue - 0.1));
}
The following assertion was thrown building PriceCounter(dirty):
BlocProvider.of() called with a context that does not contain a CounterCubit.
No ancestor could be found starting from the context that was passed to BlocProvider.of<CounterCubit>().
This can happen if the context you used comes from a widget above the BlocProvider.
The context used was: PriceCounter(dirty)
The relevant error-causing widget was PriceCounter
lib\…\widgets\filter_dialog.dart:233 When the exception was thrown,
this was the stack
Unfortunately, your FilterDialog cannot find the CounterCubit provider, since showDialog is a bit tricky about it, so you have to re-supply your CounterCubit to FilterDialog in this way:
Widget _child(context, Size size) => Padding(
padding: const EdgeInsets.only(top: 121, right: 24),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
return BlocProvider.value( // in this way
value: CounterCubit(),
child: FilterDialog(),
);
},
);
},
child: Container(
height: 40,
width: 50,
decoration: const BoxDecoration(
color: Colors.amber,
),
alignment: Alignment.center,
child: const Text('Dialog'),
),
),
),
);
}
With BlocProvider.value you do not create a Bloc, but only assign to its child the bloc that you have already created in HomePage.
That should work, but if for some reason you are going to use this CounterCubit in another page and you don't want to use BlocProvider.value again, I strongly suggest that you make it global, in other words that you provide the CounterCubit in all your application in this way :
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterCubit(), // here
child: MaterialApp(
title: 'Material App',
debugShowCheckedModeBanner: false,
home: const HomePage(),
),
);
}
}
With this, now every application will be able to get the context of your CounterCubit.
With both codes, one with the BlocProvider.value or without it and using it global, it works.

How to pass parameters using pushNamedAndRemoveUntil?

I need to pass parameters to the initial page using pushNamedAndRemoveUntil .
I need to re-pass an arg that takes color and textController.text to valueText and color on the initial page. You need to do this with pushNamedAndRemoveUntil.
Please help implement this functionality.
Screen with arg:
class TextValue extends StatefulWidget {
static const routeName = '/text_value';
const TextValue({Key? key}) : super(key: key);
#override
State<TextValue> createState() => _TextValueState();
}
class _TextValueState extends State<TextValue> {
// controller for textField
TextEditingController textController = TextEditingController();
#override
void dispose() {
textController.dispose();
super.dispose();
}
//arg variable
ColorArguments? arg;
#override
Widget build(BuildContext context) {
//get arg from ColorPickerScreen
arg ??= ModalRoute.of(context)!.settings.arguments as ColorArguments;
return Scaffold(
backgroundColor: arg?.color,
appBar: AppBar(
title: const Text('Enter a value'),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
controller: textController,
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'(^\d*\.?\d*)'))
],
style: const TextStyle(color: Colors.black),
decoration: const InputDecoration(
hintText: 'Enter a value',
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2))),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (textController.text.isEmpty) {
} else {
Navigator.pushNamedAndRemoveUntil(
context, HomeScreen.routeName, (route) => false,
);
}
},
child: const Text('Done'),
)
],
),
),
);
}
}
Initial Screen:
import 'package:flutter/material.dart';
import 'package:flutter_app/screens/color_picker_screen.dart';
class HomeScreen extends StatefulWidget {
final String valueText;
final ColorArguments? color;
static const routeName = '/home';
const HomeScreen({Key? key, required this.valueText, required this.color})
: super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// navigation to the next screen
void _colorScreen() {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const ColorPicker()));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _colorScreen, child: const Text('Choose a color')),
const SizedBox(height: 30.0),
TextFormField(
readOnly: true,
initialValue: widget.valueText,
),
const SizedBox(height: 100),
Container(
width: 50,
height: 50,
color: widget.color?.color,
),
],
),
),
);
}
}
You can use the named arguments parameter of the pushNamedAndRemoveUntil method. All you need to do is create a custom object for passing all the values you need to the push call. The arguments can be accessed in your initial screen by using
final args = ModalRoute.of(context)!.settings.arguments
You can refer to this Flutter cookbook on navigation using named routes with arguments.
Why dont you consider using Class contructors and passing data like this
Navigator.push(context,
MaterialPageRoute(builder: (context) => const ColorPicker(<Your_data>)));

Flutter: call parent function from child widget

hi there 👋🏼 i would like to call a function from a child widget (customappbar) for example to open the drawer.
there is my code:
home_page.dart
import 'package:fahrschuleapp/widget/appbar_widget.dart';
import 'package:fahrschuleapp/widget/sidebar_widget.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
drawerEnableOpenDragGesture: false,
body: SafeArea(
child: Center(
child: Column(
children: [
CustomAppBar(
pFunction: CustomAppBarFunction.menu,
pContext: context,
pTitle: 'test',
),
],
),
),
),
drawer: SideBar(),
);
}
}
i tried to say with the parameter "pFunction" which function should be called
for example navigator pop or open menu etc inside the _callFunction
appbar_widget.dart
import 'package:flutter/material.dart';
enum CustomAppBarFunction {
menu,
back,
exit,
}
class CustomAppBar extends StatelessWidget {
CustomAppBar({
Key? key,
required this.pTitle,
required this.pContext,
required this.pFunction,
}) : super(key: key);
CustomAppBarFunction pFunction;
String pTitle;
BuildContext pContext;
final List<IconData> _iconList = [
Icons.menu,
Icons.arrow_back,
Icons.close,
];
_callFunction(int index) {
switch (index) {
case 0:
Scaffold.of(pContext).openDrawer();
break;
default:
break;
}
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
margin: const EdgeInsets.all(8),
child: IconButton(
onPressed: _callFunction(pFunction.index),
icon: Icon(
_iconList[pFunction.index],
),
),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(15)),
color: Theme.of(context).colorScheme.primary,
),
),
Container(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Text(
pTitle,
style: const TextStyle(
fontFamily: 'Hellix',
fontSize: 20,
),
),
),
const SizedBox(
width: 50.4,
),
],
),
);
}
}
i tried to call inside the widget the _callFunction but this doesnt work
error output:
Scaffold.of() called with a context that does not contain a Scaffold.
how can i solve it? or is there a better way to do that?
Change you IconButton as below code,
Builder(builder: (context) {
return IconButton(
onPressed:() => _callFunction(pFunction.index, context),
icon: Icon(
_iconList[pFunction.index],
),
) ;
})
And change your _callFunction,
_callFunction(int index, BuildContext mContext) {
switch (index) {
case 0:
Scaffold.of(mContext).openDrawer();
break;
default:
break;
}
}
Scaffold.of() called with a context that does not contain a Scaffold.
This message appears when you try to access a Scaffold from a context that does not have a Scaffold above it. You can use a Key for that purpose. Create a GlobalKey and assign it to the Scaffold, then pass the Key to the AppBar from where you can access the Scaffold.

How to know the end of Hero animation in flutter?

I want to achieve this:
But when Hero animation starts keyboard is forced to dismiss:
I tried to use widgets callback which is triggered after layout. But this callback is fired whenever hero animation starts. I also tried to use Future.delayed(Duration(seconds: 2), but it does not help. Everything is working as expected if I only remove Hero widget from the widget tree.
Here is my first Screen:
import 'package:flutter/material.dart';
import 'package:move_me_delivery/components/rounded_app_bar.dart';
import 'package:move_me_delivery/components/search_field.dart';
import '../screens.dart';
class HomeTab extends StatelessWidget {
const HomeTab({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: RoundedAppBar(title: ""),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
children: [
SearchTextField(
onFocusChange: (val) async {
if(val){
await Navigator.push(context, PageRouteBuilder(
transitionDuration: Duration(milliseconds: 400),
pageBuilder: (_, __, ___) => SearchScreen()));
}
},
)
],
),
)
);
}
}
Here is my second screen:
import 'package:flutter/material.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:move_me_delivery/components/search_field.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
final _focusNode = FocusNode();
#override
void initState() {
super.initState();
_focusNode.requestFocus();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: SafeArea(
child: Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
children: [
SearchTextField(
focus: _focusNode,
onCancel: (){
FocusScope.of(context).unfocus();
Navigator.pop(context);
},
inputDecoration: InputDecoration(
prefixIcon: Icon(LineAwesomeIcons.search, color: Colors.black,),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1))
),
),
],
),
),
),
),
);
}
}
And finally here is my SearchField screen with Hero animation:
import 'package:flutter/material.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:move_me_delivery/data/styles.dart';
class SearchTextField extends StatefulWidget {
const SearchTextField({Key? key,
this.onFocusChange,
this.focus,
this.onCancel,
this.inputDecoration
}) : super(key: key);
final void Function(bool hasFocus)? onFocusChange;
final FocusNode? focus;
final VoidCallback? onCancel;
final InputDecoration? inputDecoration;
#override
_SearchTextFieldState createState() => _SearchTextFieldState();
}
class _SearchTextFieldState extends State<SearchTextField>{
late FocusNode _focus;
#override
void initState() {
super.initState();
_focus = widget.focus ?? new FocusNode();
_focus.addListener(
(){
if(widget.onFocusChange != null){
widget.onFocusChange!(_focus.hasFocus);
}
}
);
}
#override
Widget build(BuildContext context) {
return Hero(
tag: "search",
child: Material(
type: MaterialType.card,
child: Row(
children: [
Expanded(
child: TextField(style: AppTextStyles.body2,
focusNode: _focus,
decoration: InputDecoration(
prefixIcon: Icon(LineAwesomeIcons.search, color: Colors.black,),
// suffixIcon: Text("Cancel"),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Colors.blue, width: 1))
))),
if(widget.onCancel != null)
GestureDetector(
onTap: widget.onCancel,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Cancel"),
),
)
],
),
),
);
}
}
The reason of keyboard dimiss is when hero animation start flight TextField unmounted so its focus loss and then keyboard dismiss.
And why TextFiled become to be unmounted, you need to understand how Hero Animaiton work, refer this https://docs.flutter.dev/development/ui/animations/hero-animations.
do something at the end of hero, you can do like below:
child: Hero(
tag: "hero_tag",
flightShuttleBuilder: ((flightContext, animation, flightDirection, fromHeroContext, toHeroContext) {
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// the end of hero animation end
_focusNode.requestFocus();
}
});
The interface you want to achieve doesn't necessarily use Hero widgets. It can be done with other animations. But, if you wan't to use Hero, you can try a rather hacky solution:
On your Screen 1, set these two properties in your Hero's TextField:
Hero(
tag: 'search',
child: Material(
type: MaterialType.transparency,
child: TextField(
readOnly: true,
showCursor: true,
onTap: () {
Navigator.push() //to SearchScreen()
}
),
),
),
Then, on Screen 2:
Hero(
tag: 'search',
child: Material(
type: MaterialType.transparency,
child: TextField(
autofocus: true,
),
),
),
You'll have to avoid using the same SearchTextField on both screens; they each need their own as I showed. Also, you can probably remove all of that FocusNode code if you use this method.
Disclaimer: I haven't tested this code. It's just something to try
I solved this exact same issue by creating a FocusNode that'll requestFocus at the end of the hero animation. However, it is also imperative that as a return for the flightShuttleBuilder function you return a widget similar to the one on the destination, except for the fact that it won't include this FocusNode.
Here's how it looks (on the destination page):
child: Hero(
tag: 'your_tag',
flightShuttleBuilder: (_, animation, __, ___, ____) {
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_focusNode.requestFocus();
}
});
return TextField();
},
child: TextField(focusNode: _focusNode),
),

Flutter Container Overlay Widget

I want to get an image like the one below with Flutter. How should I provide this? I can provide this with container border, but I want to put a wigdet instead of border. For example, I want to wrap a circle widget with a Circleprogress bar. progress should grow as widget grows
Stack(
children: [
Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: context.themeCopyExtensions.backgroundColor,
shape: BoxShape.circle,
border: Border.all(width: 5),
boxShadow: [
BoxShadow(
color: context.themeCopyExtensions.backgroundColor,
blurRadius: 10)
]),
child: ImagesHelper.imagesHelper.getAssetImage(imageName: "logo"),
),
],
);
I implemented using 'Stack' widget and 'CircularProgressIndicator'.
(Need to adjust each widget size)
/// Flutter code sample for CircularProgressIndicator
// This example shows a [CircularProgressIndicator] with a changing value.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget>
with TickerProviderStateMixin {
AnimationController controller;
#override
void initState() {
controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 5),
)..addListener(() {
setState(() {});
});
controller.repeat(reverse: true);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: 300,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
CircularProgressIndicator(
value: controller.value,
strokeWidth: 5,
semanticsLabel: 'Linear progress indicator',
),
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xFF431CEE),
),
child: Icon(
Icons.audiotrack,
color: Colors.white,
size: 35,
),
),
],
),
),
],
),
),
);
}
}
I think I would use the FloatingActionButton to do this. You can put it anywhere in the widget tree and achieve your intended goal with much less effort than creating custom painter. It will always sit on top of your whole stack of pages using its built in overlay functionality. If you also don't want it to be clickable, you can always set the onPressed to null. One possible example is:
FloatingActionButton(
onPressed: () {},
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: context.themeCopyExtensions.backgroundColor,
shape: BoxShape.circle,
border: Border.all(width: 5),
boxShadow: [
BoxShadow(
color: context.themeCopyExtensions.backgroundColor,
blurRadius: 10,
)
],
image: DecorationImage(
image: ImagesHelper.imagesHelper.getAssetImage(imageName: "logo"),
fit: BoxFit.cover,
)),
),
)