I basically have a four-page sample app that I'm just getting started with, and I developed a custom bottom navigation bar. However, when I switch pages (using PageView and Riverpod) or tap on the BlurBottomNav buttons, it changes pages but the BlurBottomNav UI doesn't get updated. I am using flutter_riverpod: ^2.1.1
What I have tried-
I have tried to convert NavButton from stateless to consumer and get ref.watch there
I have tried StateNotifier instead of Notifier
Update: Same Code works when using ChangeNotifier with ChangeNotifierProvider but it doesn't with Notifier
Here are snippets
pageview_widget.dart
import 'package:demo/src/constants/nav_items.dart';
import 'package:demo/src/features/categories/presentation/categories_page.dart';
import 'package:demo/src/features/favourites/presentation/fav_page.dart';
import 'package:demo/src/features/pageview/data/pageview_service.dart';
import 'package:demo/src/features/pageview/presentation/bottom_nav/bottom_nav.dart';
import 'package:demo/src/features/settings/presentation/settings_page.dart';
import 'package:demo/src/features/wallpaper/presentation/wall_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class PageViewWidget extends StatefulWidget {
const PageViewWidget({super.key});
#override
State<PageViewWidget> createState() => _PageViewWidgetState();
}
class _PageViewWidgetState extends State<PageViewWidget> {
final pageController = PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Breezy'),
),
body: Consumer(
builder: (context, ref, child) {
final pageviewService = ref.watch(pageviewServiceProvider.notifier);
final pageviewServiceRead = ref.watch(pageviewServiceProvider);
return Stack(
children: [
PageView.builder(
itemCount: 4,
controller: pageController,
onPageChanged: (int index) {
pageviewService.onPageChanged(index);
// pageviewService.changeShowBNB(true);
},
itemBuilder: (context, index) {
switch (index) {
case 0:
return const WallpaperList();
case 1:
return const CategoriesPage();
case 2:
return const FavouritesPage();
case 3:
return const SettingsPage();
default:
// Should never get hit.
return CircularProgressIndicator(
color: Theme.of(context).primaryColor,
);
}
}),
Positioned.fill(
bottom: 20,
child: SafeArea(
child: BlurBottomNav(
onItemSelected: (int value) {
pageviewService.onTapByBnb(value, pageController);
},
selectedIndex: pageviewServiceRead.currentindex,
items: navItems,
),
),
),
],
);
},
));
}
}
here is pageview_service.dart
import 'package:demo/src/features/pageview/domain/pageview_navigation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class PageViewService extends Notifier<PageViewNavigation> {
#override
PageViewNavigation build() {
return PageViewNavigation(
currentindex: 0, changedByBNB: false, showBNB: true);
}
void changeShowBNB(bool value) {
state.showBNB = value;
}
void changeIndex(int index) {
state.currentindex = index;
}
void _changeBNBBool(bool value) {
state.changedByBNB = value;
}
void onPageChanged(int index) {
if ((index != state.currentindex) && (!state.changedByBNB)) {
changeIndex(index);
} else {
_changeBNBBool(false);
}
}
void onTapByBnb(int index, PageController pageController) {
if (index != state.currentindex) {
if (pageController.hasClients) {
_changeBNBBool(true);
changeIndex(index);
pageController.animateToPage(
index,
curve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 350),
);
}
}
}
}
final pageviewServiceProvider =
NotifierProvider<PageViewService, PageViewNavigation>(PageViewService.new);
here is bottom_nav.dart
import 'dart:ui';
import 'package:demo/src/features/pageview/domain/nav_button.dart';
import 'package:demo/src/features/pageview/presentation/bottom_nav/nav_buttons.dart';
import 'package:flutter/material.dart';
class BlurBottomNav extends StatelessWidget {
final List<BottomNavBarItem> items;
final ValueChanged<int> onItemSelected;
final int selectedIndex;
const BlurBottomNav({
super.key,
required this.items,
required this.onItemSelected,
required this.selectedIndex,
});
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.65,
height: 57,
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
height: 100,
color: Colors.red,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items.map((item) {
var index = items.indexOf(item);
return GestureDetector(
onTap: () => onItemSelected(index),
child: NavButton(
item: item,
isSelected: index == selectedIndex,
),
);
}).toList(),
),
),
),
),
),
),
);
}
}
here is bottom_nav_button.dart
import 'dart:ui';
import 'package:demo/src/features/pageview/domain/nav_button.dart';
import 'package:flutter/material.dart';
class NavButton extends StatelessWidget {
final BottomNavBarItem item;
final bool isSelected;
const NavButton({
super.key,
required this.item,
required this.isSelected,
});
#override
Widget build(BuildContext context) {
return Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(15),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 100,
width: 43,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: Colors.purple,
width: 2,
),
color: isSelected ? item.activeIconColor : Colors.white,
),
child: item.icon,
),
),
),
],
);
}
}
and lastly here is BottomNavBarItem
import 'package:flutter/material.dart';
class BottomNavBarItem {
BottomNavBarItem({
required this.icon,
required this.activeIconColor,
});
final Widget icon;
final Color activeIconColor;
}
I haven't used flutter in a while, so please be gentle with me
Keep in mind that you can't use mutable state like this in your Notifier subclasses:
state.showBNB = value;
Instead it should be:
state = /* new state */
If you have a custom state class, make sure all properties are final and add a copyWith method.
Related
I am using flutter river pods for this project. I want to change the API call when pressing on the second and third tab. I.e make the JSON API link dynamic. How can I do that?
Each widget is in its different file
Here is my code
main.dart
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: true,
home: HomeView(),
);
}
}
Home_views.dart
class HomeView extends ConsumerWidget {
const HomeView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
TabController controller;
final ModelView = ref.watch(getFutureData);
return Consumer(
builder: (context, WidgetRef ref, _) {
return TabBarWidget;
}
);
}
}
Data_model.dart
class DataModel {
const DataModel({
required this.id,
required this.joke,
required this.categories,
});
final int id;
final String joke;
final String categories;
}
data_controllers.dart
final getFutureData = ChangeNotifierProvider<GetApiDATA>((ref) => GetApiDATA());
class GetApiDATA extends ChangeNotifier{
List<DataModel> ListOfDataModels = [];
GetApiDATA(){
getDataApi();
}
Future getDataApi() async {
ListOfDataModels = [];
try{
http.Response ApiResponse = await http.get(Uri.parse("https://v2.jokeapi.dev/joke/Programming?type=single&contains=joke&amount=10"));
if (ApiResponse.statusCode == 200) {
final body = jsonDecode(ApiResponse.body) as Map<String, dynamic>;
if (body['error'] == false) {
final jokes = body['jokes'];
for (final joke in jokes) {
final jokeMap = joke as Map<String, dynamic>;
print("jokeText is ${jokeMap['joke']}");
final id = jokeMap['id'] as int;
final jokeText = jokeMap['joke'] as String;
final categories = jokeMap['category'] as String;
ListOfDataModels.add(DataModel(id: id, joke: jokeText, categories: categories));
}
print("Length is ${ListOfDataModels.length}");
notifyListeners();
}
}
}
catch(e)
{
print(e.toString());
}
}
}
TabBarWidget.dart
import 'package:assignment_moe/Controllers/data_controllers.dart';
import 'package:assignment_moe/Widgets/TabViewWidget.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Widget TabBarWidget = Consumer(
builder: (context, WidgetRef ref, _) {
final ModelView = ref.watch(getFutureData);
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
backgroundColor: Color(0XffF7F7F7),
appBar: AppBar(
backgroundColor: Color(0xff1B9C8F),
title: Text('Jokes API'),
),
body: Column(
children: [
Container(
margin: const EdgeInsets.only(top: 30, left: 10,right: 10),
height: 35,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
),
child: TabBar(
indicator: BoxDecoration(
color: Color(0xff1B9C8F),
borderRadius: BorderRadius.all(Radius.circular(10)),
),
labelColor: Colors.white,
unselectedLabelColor: Color(0xff1B9C8F),
tabs: [
Tab(
text: 'Programming',
),
Tab(
text: 'Dark',
),
Tab(
text: 'Spooky',
),
],
),
),
Expanded(
child: TabBarView(
children: [
TabViewWidget,
TabViewWidget,
TabViewWidget,
],
),
),
],
),
),
),
);
}
);
TabViewWidget.dart
import 'package:assignment_moe/Controllers/data_controllers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Widget TabViewWidget = Consumer (
builder: (context, WidgetRef ref, _) {
final ModelView = ref.watch(getFutureData);
return ModelView.ListOfDataModels.isEmpty ?
Center(child: CircularProgressIndicator(),) :
ListView.builder(
itemCount: ModelView.ListOfDataModels.length,
itemBuilder: (context, index) =>
Container(
margin: EdgeInsets.only(top: 20,left: 20,right: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListTile(
title: Text(ModelView.ListOfDataModels[index].categories
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 10),
child: Text(ModelView.ListOfDataModels[index].joke),
),
leading: Container(
alignment: Alignment.center,
width: 35,
height: 35,
decoration: BoxDecoration(
color: Color(0xff1B9C8F),
borderRadius: BorderRadius.circular(20)),
child: Text(
ModelView.ListOfDataModels[index].id.toString(),
style: TextStyle(color: Colors.white),
),
),
),
),
),
);
}
);
Below is the screen shot
ANy help would be appreciated
I am a newbie in flutter and this is my first real use app.
This is what i want to achieve my app is going to be used to detect number-plates automatically when the camera would be pointed on the numberplate, for the text detection part i am going to use flutter ml kit. How should i write the start image stream method if i want the output of 10 images in the File data type which I would then add to my ImagePathList.
I did do research on this, but i did not find anything related to what i wanted to achieve, there are a few blog posts using this but they have not explained it properly so i turned to stack overflow.
I want the functionality to be like this
This is what my camera_screen looks like
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:firebase_ml_vision/firebase_ml_vision.dart';
import 'package:flutter/services.dart';
import 'package:npgroups/npgroups.dart';
import 'package:society_app/screens/result_screen.dart';
import 'package:society_app/widgets/common_drawer.dart';
import 'package:camera/camera.dart';
import 'dart:async';
import 'package:numeric_keyboard/numeric_keyboard.dart';
class CameraScreen extends StatefulWidget {
final CameraDescription camera;
static String id = 'camera_screen';
CameraScreen({required this.camera});
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
Widget buildButton(String buttonText){
return Container(
height: MediaQuery.of(context).size.height * 0.1 * 0.85,
color: Colors.blueAccent,
child: FlatButton(
onPressed: () {},
child: Text(
buttonText,
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.normal,
color: Colors.white
),
)
),
);
}
late CameraController _controller;
late Future<void> _initializeControllerFuture;
late Npgroups _npgroups;
List imagePathList = [];
List<String?> detectedWordList = [];
static const MethodChannel _channel = const MethodChannel('tflite');
String? resultText;
late int imageHeight;
late int imageWidth;
bool? get isPaused => null;
#override
void initState() {
// TODO: implement initState
super.initState();
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
_initializeControllerFuture = _controller.initialize();
initPlatformState();
}
Future<void> initPlatformState() async {
_npgroups = Npgroups(listenToNumplate);
await _npgroups.startListening();
}
#override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
Future getNumberPlate(image) async {
FirebaseVisionImage mlImage = FirebaseVisionImage.fromFile(image);
TextRecognizer recognizeText = FirebaseVision.instance.textRecognizer();
VisionText readText = await recognizeText.processImage(mlImage);
for (TextBlock block in readText.blocks) {
for (TextLine line in block.lines) {
for (TextElement word in line.elements) {
resultText = word.text;
_npgroups.processNumberplate(resultText!);
}
}
}
if (resultText == null) {
print('null');
} else {
detectedWordList.add(resultText);
}
}
listenToNumplate(String numplate) {
//Consume the numplate
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: CommonDrawer(),
appBar: AppBar(
title: Text(
'Camera'
),
),
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
AspectRatio(aspectRatio: _controller.value.aspectRatio - 0.2,
child: CameraPreview(_controller)),
Positioned(
bottom: 10,
left: 5,
child: Row(
children: [
VehicleButton(icon: Icons.motorcycle_outlined,),
SizedBox(width: 35),
VehicleButton(icon: Icons.directions_car,)
],
),
)
],
),
Row(
children: [
Container(
width: MediaQuery.of(context).size.width * .99,
child: Table(
children: [
TableRow(
children: [
buildButton('1'),
buildButton('2'),
buildButton('3')
]
),
TableRow(
children: [
buildButton('4'),
buildButton('5'),
buildButton('6')
]
),
TableRow(
children: [
buildButton('7'),
buildButton('8'),
buildButton('9')
]
),
TableRow(
children: [
buildButton('↻'),
buildButton('0'),
buildButton('⌫')
]
),
],
),
)
],
)
],
);
} else {
// Otherwise, display a loading indicator.
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
}
class VehicleButton extends StatelessWidget {
final IconData icon;
VehicleButton({required this.icon});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 17, horizontal: 50),
child: Icon(
icon,
color: Colors.white,
size: 45,
),
),
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)))
),
);
}
}
Blockquote
You can do something like that
#override
void initState() {
super.initState();
controller = CameraController(widget.cameras[0], ResolutionPreset.medium,
enableAudio: false);
controller.initialize().then((_) async {
if (!mounted) {
return;
}
setState(() {});
await controller.startImageStream((CameraImage availableImage) async {
_scanText(availableImage);
});
}
i am making a wallpaper app in flutter, i made wallpaper grids and i want to implement native ads in this GridView but i am not getting how to?
Can someone please help me to implement, i have tried a lot of things but none of them worked for me
This is what i want -
Here i want to implement -
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import '../views/wallpaper.dart';
import '../../core/utils/models/response.dart';
class WallpaperList extends StatefulWidget {
final List<Post> posts;
final ThemeData themeData;
WallpaperList({#required this.posts, #required this.themeData});
#override
_WallpaperListState createState() => _WallpaperListState();
}
class _WallpaperListState extends State<WallpaperList> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return widget.posts.length == 0
? SizedBox(
height: 200,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(FontAwesomeIcons.sadCry,
size: 30, color: widget.themeData.accentColor),
),
Text(
'Seems like what you are looking for, is empty.',
style: widget.themeData.textTheme.body2,
)
],
),
)
: wallpaperGrid(widget.posts);
}
Widget wallpaperGrid(List<Post> list) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, childAspectRatio: 0.7),
padding: const EdgeInsets.all(0),
itemCount: list.length,
shrinkWrap: true,
physics: ScrollPhysics(),
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WallpaperPage(
heroId: 'popular${list[index].name}',
posts: list,
index: index,
)));
},
child: Hero(
tag: 'popular${list[index].name}',
child: SizedBox(
width: double.infinity,
height: 300,
child: ClipRRect(
borderRadius: BorderRadius.circular(15.0),
child: CachedNetworkImage(
errorWidget: (context, url, error) => Container(
width: double.infinity,
height: double.infinity,
child: Center(
child: Icon(
Icons.error,
color: widget.themeData.accentColor,
),
),
),
fit: BoxFit.cover,
placeholder: (context, url) => Center(
child: Container(
width: double.infinity,
height: double.infinity,
color: widget.themeData.primaryColorDark,
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(
widget.themeData.accentColor),
))),
),
imageUrl:
list[index].preview.images[0].resolutions.length <= 3
? widget
.posts[index]
.preview
.images[0]
.resolutions[list[index]
.preview
.images[0]
.resolutions
.length -
1]
.url
.replaceAll('amp;', '')
: list[index]
.preview
.images[0]
.resolutions[3]
.url
.replaceAll('amp;', ''),
),
),
),
),
),
);
},
);
}
}
Please help, any help would be appreciated
Below is the Example for Implement Admob Native ads in Staggered GridView in flutter
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_native_admob/flutter_native_admob.dart';
import 'package:flutter_native_admob/native_admob_controller.dart';
import 'package:cached_network_image/cached_network_image.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _list = List<IMageClass>();
static const _adUnitID = "ca-app-pub-3940256099942544/8135179316";
final _nativeAdController = NativeAdmobController();
double _height = 0;
#override
void initState() {
super.initState();
_getData();
}
Widget Images(int index) {
return CachedNetworkImage(
imageUrl: _list[index].images,
placeholder: (context, string) {
return Center(
child: CupertinoActivityIndicator(),
);
},
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
errorWidget: (context, url, error) => Icon(Icons.error),
);
}
List<String> imageList = [
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f',
'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e',
'https://images.unsplash.com/photo-1513956589380-bad6acb9b9d4',
'https://images.unsplash.com/photo-1521577352947-9bb58764b69a',
'https://images.unsplash.com/photo-1488161628813-04466f872be2',
'https://images.unsplash.com/photo-1501196354995-cbb51c65aaea',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f',
'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e',
'https://images.unsplash.com/photo-1513956589380-bad6acb9b9d4',
'https://images.unsplash.com/photo-1521577352947-9bb58764b69a',
'https://images.unsplash.com/photo-1488161628813-04466f872be2',
'https://images.unsplash.com/photo-1501196354995-cbb51c65aaea',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f',
'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e',
'https://images.unsplash.com/photo-1513956589380-bad6acb9b9d4',
'https://images.unsplash.com/photo-1521577352947-9bb58764b69a',
'https://images.unsplash.com/photo-1488161628813-04466f872be2',
'https://images.unsplash.com/photo-1501196354995-cbb51c65aaea',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f',
'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e',
'https://images.unsplash.com/photo-1513956589380-bad6acb9b9d4',
'https://images.unsplash.com/photo-1521577352947-9bb58764b69a',
'https://images.unsplash.com/photo-1488161628813-04466f872be2',
'https://images.unsplash.com/photo-1501196354995-cbb51c65aaea',
'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f',
'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e',
'https://images.unsplash.com/photo-1513956589380-bad6acb9b9d4',
'https://images.unsplash.com/photo-1521577352947-9bb58764b69a',
'https://images.unsplash.com/photo-1488161628813-04466f872be2',
'https://images.unsplash.com/photo-1501196354995-cbb51c65aaea',
];
void _getData() {
for (int i = 0; i < imageList.length; i++) {
var image = IMageClass();
if (i != 0) {
if (i % 4 == 3) {
image.type = "GoogleAd";
} else {
image.type = "";
image.images = imageList[i];
}
_list.add(image);
} else {
image.type = "";
image.images = imageList[i];
_list.add(image);
}
}
}
Widget _getAdContainer() {
return Container(
height: 250,
child: NativeAdmob(
// Your ad unit id
adUnitID: "ca-app-pub-3940256099942544/8135179316",
controller: _nativeAdController,
type: NativeAdmobType.banner,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.all(12),
child: StaggeredGridView.countBuilder(
crossAxisSpacing: 3.0,
mainAxisSpacing: 3.0,
// controller: scrollController,
itemCount: _list.length,
physics: ScrollPhysics(),
itemBuilder: (context, index) {
if (_list[index].type != "GoogleAd")
return Images(index);
else
return _getAdContainer();
},
crossAxisCount: 2,
staggeredTileBuilder: (int index) {
if (_list[index].type != "GoogleAd")
return StaggeredTile.count(1, 1);
else
return StaggeredTile.count(2, 1);
// return StaggeredTile.count(1, 1);
},
)),
);
}
}
class IMageClass {
String images;
String type;
}
How can I use Flutter to print in Sunmi V2?
I am trying to use this package: https://pub.dev/packages/sunmi
But there is no clear explanation of how to use it
There is a new flutter plugin for Sunmi printers: flutter_sunmi_printer
It can print texts with styles (bold, underline, align, font size), tables (using Bootstrap-like grid system), images etc.
import 'package:flutter_sunmi_printer/flutter_sunmi_printer.dart';
// Text with styles
SunmiPrinter.text('left');
SunmiPrinter.text(
'center',
styles: SunmiStyles(bold: true, underline: true, align: SunmiAlign.center),
);
SunmiPrinter.text(
'right',
styles: SunmiStyles(bold: true, underline: true, align: SunmiAlign.right),
);
// Table
SunmiPrinter.row(
cols: [
SunmiCol(text: 'col1', width: 4),
SunmiCol(text: 'col2', width: 4, align: SunmiAlign.center),
SunmiCol(text: 'col3', width: 4, align: SunmiAlign.right),
],
);
// Image
ByteData bytes = await rootBundle.load('assets/rabbit_black.jpg');
final buffer = bytes.buffer;
final imgData = base64.encode(Uint8List.view(buffer));
SunmiPrinter.image(imgData);
You can see github https://github.com/irpankusuma/SUNMI_AIDL_PRINTER
Full example code https://github.com/irpankusuma/SUNMI_AIDL_PRINTER/tree/master/example
In pubspec.yaml manually add
assets:
- assets/images/
from widget/config.dart add the following png and jpg to assets/images
const String defaultLogoImage = "assets/images/logo.png";
const String defaultPrintLogoImage = "assets/images/print-logo.png";
const String defaultErrorImage = "assets/images/error_404.jpg";
Print Page
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sunmi_aidl_print_example/blocs/blocs.dart';
import 'package:sunmi_aidl_print_example/blocs/printing_bloc.dart';
import 'package:sunmi_aidl_print_example/config.dart' as config;
import 'package:flutter/material.dart';
import 'package:sunmi_aidl_print/models.dart';
import 'package:sunmi_aidl_print/sunmi_aidl_print.dart';
import 'package:sunmi_aidl_print_example/models/models.dart';
import 'package:sunmi_aidl_print_example/common/common.dart';
class PrintingPage extends StatefulWidget {
#override
State<PrintingPage> createState() => PrintingPageState();
}
class PrintingPageState extends State<PrintingPage>{
List<SunmiPrinter> array = <SunmiPrinter>[];
List<MenuService> menus = <MenuService>[];
Uint8List bytes;
#override
void initState() {
super.initState();
_getBytesImage();
SunmiAidlPrint.bindPrinter();
}
#override
void dispose() {
super.dispose();
SunmiAidlPrint.unbindPrinter();
}
void _getBytesImage() async{
ByteData getBytes = await rootBundle.load(config.defaultPrintLogoImage);
Uint8List image = getBytes.buffer.asUint8List();
setState(() => bytes = image);
}
void _generateMenu() {
menus.add(new MenuService(
name:'TEXT',
icons: Icon(Icons.text_fields),
onTap: () => null
));
}
void _openAlert({ String error}){
showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Alert'),
content: new Text(error),
)
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('PRINT EXAMPLE'),
),
body: new Container(
child: BlocListener<PrintingBloc,PrintingState>(
listener: (context,state){
if(state is ErrorPrinting){ _openAlert(error:state.error); }
},
child: BlocBuilder<PrintingBloc,PrintingState>(
builder: (context,state){
if(state is LoadingPrinting){ return new LoadingIndicator(); }
if(state is InitialPrinting){
return new Container(
child: new MenuServiceState(items:menus,),
);
}
if(state is LoadedPrinting){
return new Container(
child: new MenuServiceState(items:menus,),
);
}
new Container();
},
),
),
),
);
}
}
class MenuServiceState extends StatelessWidget {
final List<MenuService> items;
final int crossAxis;
MenuServiceState({ this.items, this.crossAxis=3 });
#override
Widget build(BuildContext context) {
return new Container(
margin: EdgeInsets.only(top:8.0,bottom:8.0),
child: new GridView.builder(
shrinkWrap: true,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:crossAxis),
physics: ClampingScrollPhysics(),
itemCount: items.length,
itemBuilder: (context,i) => new GestureDetector(
onTap: () => items[i].onTap,
child: new Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Container(
decoration: new BoxDecoration(
border: Border.all(color:Colors.grey,width:1.0),
borderRadius: new BorderRadius.all(new Radius.circular(20.0))
),
padding: EdgeInsets.all(12.0),
child: items[i].icons,
),
new Padding(padding: EdgeInsets.only(top:6.0),),new Text("${items[i].name}")
],
),
),
),
),
);
}
}
Hi I have a screen for adding images. I use the multi_image_picker for picking the images. Upon selection of the images, all images picked will be shown in a grid view with a FloatingActionButton on top of each image for removal of each image. The problem is, when I click the button for removing an image, the last image is removed not the one I clicked on. Has anyone experienced this?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:krakatoa/api/FileApi.dart';
import 'package:krakatoa/components/AssetView.dart';
import 'package:krakatoa/config/Themes.dart' as themes;
import 'package:krakatoa/mixins/SnackBarMixin.dart';
import 'package:krakatoa/podos/User.dart';
import 'package:krakatoa/utils/Common.dart' as common;
import 'package:multi_image_picker/multi_image_picker.dart';
class AddImageScreen extends StatefulWidget {
final List<String> currentImageUrls;
final String postUrl;
AddImageScreen({this.currentImageUrls, #required this.postUrl});
#override
State<StatefulWidget> createState() => _AddImageState();
}
class _AddImageState extends State<AddImageScreen> with SnackBarMixin {
List<Asset> _images = [];
User _user;
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: Text('Add images'),
),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView(
children: <Widget>[
Container(
padding: EdgeInsets.only(bottom: 10),
child: Text(
"Upload Images:",
style: Theme.of(context).textTheme.headline,
),
),
Container(
padding: EdgeInsets.only(bottom: 10),
child: GridView.count(
shrinkWrap: true,
crossAxisSpacing: 3,
mainAxisSpacing: 3,
crossAxisCount: 3,
children: _renderPickedImages(),
),
),
Container(
child: FlatButton(
child: Text('UPLOAD'),
padding: EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
color: themes.primaryColor,
onPressed: _onUploadBtnPress,
),
),
],
),
),
);
}
#override
void dispose() {
super.dispose();
for (var image in _images) {
image.release();
}
}
#override
void initState() {
super.initState();
common.getCurrentUser().then((user) {
if (user != null) {
_user = user;
} else {
_user = User();
}
});
}
void showProgressAlert() {
showDialog(
context: context,
builder: (context) {
return WillPopScope(
onWillPop: () async => false,
child: AlertDialog(
content: ListTile(
leading: CircularProgressIndicator(
value: null,
),
title: Text('Processing...'),
),
),
);
},
barrierDismissible: false,
);
}
void _onAddImageBtnPress() async {
List<Asset> resultList;
try {
resultList = await MultiImagePicker.pickImages(maxImages: 5, enableCamera: true);
} on PlatformException catch (e) {
debugPrint("AddImageScreen._onAddImageBtnPress: ${e.toString()}");
}
if (!mounted) return;
if (resultList.isNotEmpty) {
setState(() {
_images.addAll(resultList);
});
}
}
void _onUploadBtnPress() {
if (_images.isNotEmpty) {
showProgressAlert();
_uploadImages();
} else {
showSnackBarMessage("No images to upload", seconds: 5);
}
}
void _removeImage(int index, Asset image) {
debugPrint("INDEX: $index");
debugPrint("Orig Image: ${_images[index].hashCode}");
setState(() {
_images.removeAt(index);
});
}
List<Widget> _renderPickedImages() {
List<Widget> imageWidgets = [];
imageWidgets.add(InkWell(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
),
child: Center(
child: Icon(
Icons.add,
size: 60,
color: Colors.grey,
),
),
),
onTap: _onAddImageBtnPress,
));
var ctr = 0;
for (var image in _images) {
imageWidgets.add(Container(
child: Stack(
fit: StackFit.expand,
overflow: Overflow.visible,
children: <Widget>[
AssetView(image),
Positioned(
bottom: 0,
right: 0,
child: _ImageRemoveButton(
index: ctr,
removeItem: _removeImage,
image: image,
),
),
],
),
));
ctr++;
}
return imageWidgets;
}
Future<void> _uploadImages() async {
if (_user.id <= 0) {
showSnackBarMessage("User is not logged in");
Navigator.of(context).pop("User is not logged in");
return;
}
try {
await FileApi.uploadImages(widget.postUrl, _images);
Navigator.of(context).pop();
Navigator.of(context).pop("Success");
} on Exception catch (e) {
debugPrint(e.toString());
showSnackBarMessage(e.toString());
Navigator.of(context).pop(e.toString());
}
}
}
class _ImageRemoveButton extends StatelessWidget {
final Function removeItem;
final Asset image;
final int index;
_ImageRemoveButton({this.removeItem, this.index, this.image});
#override
Widget build(BuildContext context) {
return FloatingActionButton(
backgroundColor: Colors.white,
mini: true,
heroTag: "ImageAction_$index",
isExtended: false,
child: Icon(
Icons.close,
size: 15,
color: Colors.black,
),
onPressed: _onPress,
);
}
void _onPress() {
debugPrint("${this.hashCode}");
debugPrint("Passed Image: ${image.hashCode}");
removeItem(index, image);
}
}
add key: Key(YOUR_LIST.length.toString()),
having KEY helps with the update of the ListView
that worked for me on ListView.builder