I know Stack Widgets render their children from the ground up, however, I couldn't explain to myself why a BlocBuilder cannot efficiently rebuild them.
Here is an example:
#override
Widget build(BuildContext context) {
return Container(
child: BlocBuilder<TestCubit, int>(
builder: (context, state) {
return GestureDetector(
onTapDown: (tapDetails) {
context.read<TestCubit>().incrementCubit();
},
child: Stack(children: [Text('Counter: $state')]),
);
},
)
);
}
When TestCubit has its incrementCubit method called, the state changes - I tested it with a simple Container based UI, but once we are dealing with a Stack, nothing happens on the screen. Any ideas?
Thanks in advance!
I tested your code and it works with both Stack as well as Container. Please see my code below :
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(
const CounterApp(),
);
}
class CounterApp extends MaterialApp {
const CounterApp({Key key}) : super(key: key, home: const CounterPage());
}
class CounterPage extends StatelessWidget {
const CounterPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => TestCubit(),
child: CounterView(),
);
}
}
class CounterView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(child: BlocBuilder<TestCubit, int>(
builder: (context, state) {
return GestureDetector(
onTapDown: (tapDetails) {
context.read<TestCubit>().incrementCubit();
},
child: Stack(children: [Text('Counter: $state')]),
//child: Text('Counter: $state'),
//child: Scaffold(
// appBar: AppBar(title: const Text("Cubit Demo")),
// body: Center(
// child: Stack(
// children: [
// Text('Counter: $state'),
// ],
// )),
//),
);
},
));
}
}
class TestCubit extends Cubit<int> {
TestCubit() : super(0);
void incrementCubit() => emit(state + 1);
void decrementCubit() => emit(state - 1);
}
pubspec.yaml
name: test_http
description: A new Flutter application.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
flutter_bloc:
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
Related
Hi im new to flutter and making a drawing app. I making a Icon button that show overlay implemented Slider widget.
this is my code and Im using a Provider package.
main.dart
void main() {
runApp(MyApp());
}
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 MaterialApp(
home:
ChangeNotifierProvider(
create: (context) => DrawingProvider(),
child: BlankPage()),
),
);
}
// Main Page
class BlankPage extends StatefulWidget {
const BlankPage({Key? key}) : super(key: key);
#override
State<BlankPage> createState() => _BlankPageState();
}
class _BlankPageState extends State<BlankPage> {
#override
Widget build(BuildContext context) {
var p = Provider.of<DrawingProvider>(context);
return GestureDetector(
child: Scaffold(
appBar: AppBar(title: Text('Workbook Test')),
body: Column(
children: [
Container(
width: double.infinity,
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
penWidget(p: p),
highlighterWidget(p: p),
erasePenWidget(p: p),
SliderOverlayWidget(),
.
.
.
// ... Slider Overlay Widget I tried to make
class SliderOverlayWidget extends StatefulWidget {
const SliderOverlayWidget({
Key? key,
}) : super(key: key);
#override
State<SliderOverlayWidget> createState() => _SliderOverlayWidgetState();
}
class _SliderOverlayWidgetState extends State<SliderOverlayWidget> {
OverlayEntry? entry;
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) => showOverlay() );
}
#override
Widget build(BuildContext context) {
return Container(
width: 60,
child: FittedBox(
fit: BoxFit.fitWidth,
child: GestureDetector(
onTap: () {
showOverlay();
},
child: Icon(
Icons.horizontal_rule_rounded,
color: Colors.black54,
),
),
),
);
}
void showOverlay() {
final overlay = Overlay.of(context)!;
entry = OverlayEntry(builder: (context) => buildSliderOverlay(),);
overlay.insert(entry!);
}
}
StatefulWidget buildSliderOverlay() {
return StatefulBuilder(
builder: (context, setState) {
var p = Provider.of<DrawingProvider>(context);
return Container(
width: 100,
child: Row(
children: [
Slider(value: p.penSize, onChanged: (size) {
p.changePenSize = size;
},
min: 3,
max: 15,)
],
),
);
},
);
}
DrawingProvider.dart
class DrawingProvider extends ChangeNotifier {
// pen size
double _penSize = 3;
double get penSize => _penSize;
set changePenSize(double size) {
_penSize = penSize;
notifyListeners();
}
when I run the App, errors are like
Erros
Error: Could not find the correct Provider<DrawingProvider> above this StatefulBuilder Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that StatefulBuilder is under your MultiProvider/Provider<DrawingProvider>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>().toString()),
);
}
```
consider using `builder` like so:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context, child) {
// No longer throws
return Text(context.watch<Example>().toString());
}
);
}
```
If none of these solutions work, consider asking for help on StackOverflow:
Thank you
I referenced this
https://www.youtube.com/watch?v=OOEyJ0ct0Sg
How to show Slider dialog widget in flutter
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main(List args) {
runApp(GetMaterialApp(
title: 'My App',
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Get.snackbar(
'Hello',
'Hello World!',
snackPosition: SnackPosition.TOP,
);
},
child: Text('GetX Buttom')),
],
),
),
);
}
}
have you imported the get package? if not, you can add it in pubspec.yaml file, inside dev_dependencies.
example:
dev_dependencies:
flutter_test:
sdk: flutter
get: ^4.6.1
then save your pubspec.yaml file and type flutter pub get in your terminal
the result will be like this:
you can read more about getX in this documentation
I'm trying to get AnimatedSwitcher to work in a ReorderableListView, it works in a normal ListView. I'm thinking it has something to do with the keys, but I'm now sure.
Flutter 1.17.0 • channel beta • https://github.com/flutter/flutter.git
Framework • revision e6b34c2b5c (7 days ago) • 2020-05-02 11:39:18 -0700
Engine • revision 540786dd51
Tools • Dart 2.8.1
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ChangeNumber(),
child: MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: SafeArea(
child: Consumer<ChangeNumber>(
builder: (context, value, child) {
return Column(
children: <Widget>[
Container(
height: 100,
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {},
children: <Widget>[
AnimatedSwitcher(
key: ValueKey(value.i),
duration: Duration(seconds: 1),
child: NumberTile(
number: value.i,
key: ValueKey(value.i),
),
),
],
),
),
RaisedButton(
child: Text('Increase'),
onPressed: () => value.i = value.i + 1,
)
],
);
},
),
),
),
),
);
}
}
class NumberTile extends StatelessWidget {
final int number;
NumberTile({this.number, key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListTile(
title: Text('$number'),
);
}
}
class ChangeNumber extends ChangeNotifier {
int _i = 0;
get i => _i;
set i(int value) {
_i = value;
notifyListeners();
}
}
AnimatedSwitcher will not show effect on Text widget as your Text is inside ListTile inside NumberTile. You have to place the direct widget which you want to animate the switch inside the AnimatedSwitcher. Check this example
I have 3 Widget MyApp Widget ,Home Widget, and Sliver Appbar Widget, It's connected to each other. Example MyApp Widget -> Home Widget -> SliverAppbar Widget.
My question is , how to Passing data from My App Widget directly to SliverAppBar Widget ?
I found what i think it's can solve my case that is Inherited Widget. But i confused to understading to use this widget.
I already try using Inherited Widget as documentation like this :
MyApp Widget
class SettingsApp extends InheritedWidget {
SettingsApp({Key key, this.isDarkMode = false, Widget child})
: super(key: key, child: child);
final bool isDarkMode;
static SettingsApp of(BuildContext context) {
return (context.dependOnInheritedWidgetOfExactType<SettingsApp>());
}
#override
bool updateShouldNotify(SettingsApp oldWidget) {
return true;
}
}
SliverAppBar Widget
class SliverAppBarCustom extends StatelessWidget {
final Box detbBox = Hive.box("debt_box");
final UserModelHive userModelHive = Hive.box("user_box").get("userSession");
#override
Widget build(BuildContext context) {
final isDarkMode =
context.dependOnInheritedWidgetOfExactType<SettingsApp>().isDarkMode;
print(isDarkMode.toString());
var mediaQuery = MediaQuery.of(context);
var textTheme = Theme.of(context).textTheme;
return Text(isDarkMode.toString());
}
}
But i get this error :
Log
The following NoSuchMethodError was thrown building SliverAppBarCustom(dirty):
The getter 'isDarkMode' was called on null.
Receiver: null
Tried calling: isDarkMode
Using ScopedModel
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
void main() => runApp(MyApp());
class SettingsModel extends Model {
bool _isDarkMode;
SettingsModel({bool isDarkMode}) : _isDarkMode = isDarkMode ?? false;
bool get isDarkModel => _isDarkMode;
set isDarkModel(bool value) {
_isDarkMode = value;
notifyListeners();
}
void switchTheme() {
_isDarkMode = !_isDarkMode;
notifyListeners();
}
static SettingsModel of(BuildContext context) {
return ScopedModel.of<SettingsModel>(context);
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScopedModel<SettingsModel>(
model: SettingsModel(isDarkMode: true),
child: MaterialApp(
home: InitPage(),
),
);
}
}
class InitPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Init Page")),
body: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ScopedModelDescendant<SettingsModel>(
builder: (context, child, model) {
return Text('Is Dark Mode: ${model.isDarkModel}');
},
),
RaisedButton(
child: Text("Next Page"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
),
);
},
),
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Page"),
),
body: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ScopedModelDescendant<SettingsModel>(
builder: (context, child, model) {
return Text('Is Dark Mode: ${model.isDarkModel}');
},
),
RaisedButton(
child: Text("Switch Theme"),
onPressed: SettingsModel.of(context).switchTheme,
),
],
),
),
);
}
}
Important: You should not change _isDarkModel without notifyListeners(). If you do UI may not update.
How do I set the image for a switch button in flutter using the activeThumbImage property? I am a little confused on how to set the ImageProvider value for this property? Is there any example that I could look at that implements the activeThumbImage property of the Switch widget?
You can use an AssetImage or NetworkImage to get an ImageProvider that is suitable for use as an activeThumbImage. Learn more about asset images in the Adding Assets and Images in Flutter tutorial.
Here is some example code that draws the above Switch:
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
MyHomePageState createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
bool _enabled;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Switch(
value: _enabled,
onChanged: (bool value) {
setState(() {
_enabled = value;
});
},
activeThumbImage: new NetworkImage('https://lists.gnu.org/archive/html/emacs-devel/2015-10/pngR9b4lzUy39.png'),
inactiveThumbImage: new NetworkImage('http://wolfrosch.com/_img/works/goodies/icon/vim#2x'),
),
)
);
}
}
void main() {
runApp(new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.deepPurple,
),
home: new MyHomePage(),
));
}
Here is my code.
class ToggleButtonScreen extends StatefulWidget {
#override
_ToggleButtonScreenState createState() => _ToggleButtonScreenState();
}
class _ToggleButtonScreenState extends State<ToggleButtonScreen> {
bool _value = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: _value ? AssetImage("images/cnw.png") : AssetImage("images/cnw.png"),
fit: BoxFit.cover,
),
),
child: Padding(
padding: EdgeInsets.all(AppDimens.EDGE_REGULAR),
child: Column(
children: [
_normalToggleButton(),
],
),
),
),
),
),
);
}
Widget _normalToggleButton () {
return Container(
child: Transform.scale(
scale: 2.0,
child: Switch(
activeColor : Colors.greenAccent,
inactiveThumbColor: Colors.redAccent,
value: _value,
activeThumbImage: AssetImage("images/cnw.png"),
inactiveThumbImage : AssetImage("images/simple_interest.png"),
onChanged: (bool value){
setState(() {
_value = value;
});
},
),
),
);
}
}
pubspec.yaml
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_inappwebview: ^5.3.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_launcher_icons: "^0.8.0"
flutter_icons:
android: "launcher_icon"
ios: true
image_path: "assets/icon/icon.png"
assets:
- assets/icon/google.png
main.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class MyChromeSafariBrowser extends ChromeSafariBrowser {
#override
void onOpened() {
print("ChromeSafari browser opened");
}
#override
void onCompletedInitialLoad() {
print("ChromeSafari browser initial load completed");
}
#override
void onClosed() {
print("ChromeSafari browser closed");
}
}
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
}
runApp(MaterialApp(home: MyApp(), theme: new ThemeData(scaffoldBackgroundColor: const Color(0xFFA7A5A5)),
debugShowCheckedModeBanner: false));
}
class MyApp extends StatefulWidget {
final ChromeSafariBrowser browser = new MyChromeSafariBrowser();
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Image Button"),
),
body:
SingleChildScrollView(
scrollDirection: Axis.vertical,
child:
Column(children: <Widget>[
Container(
// padding: EdgeInsets.all(50),
alignment: Alignment.center,
child: IconButton(
icon: Image.asset('assets/icon/Amazon_icon.png'),
iconSize: 50,
color: Colors.green,
splashColor: Colors.purple,
onPressed: () async {
await widget.browser.open(
url: Uri.parse("https://www.amazon.in/?&_encoding=UTF8&tag=bappasaikh-21&linkCode=ur2&linkId=e3b009b026920c3cfdd6185fadfb7e67&camp=3638&creative=24630"),
options: ChromeSafariBrowserClassOptions(
android: AndroidChromeCustomTabsOptions(
addDefaultShareMenuItem: false,),
ios: IOSSafariOptions(barCollapsingEnabled: true)));
},
),
),
]),
),
);
}
}