Flutter: Using image instead of icon - image

I have a sample code for a radiostream player.
The code provides for an icon to represent its state (paused or playing).
I would like to show an image instead of the icon.
Being a newby/noob with flutter im stuck.
Can sonebody push me in the right direction?
Here is the current code:
...........
default:
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () async {
print("button press data: " +
snapshot.data.toString());
await _flutterRadioPlayer.playOrPause();
},
icon: snapshot.data ==
FlutterRadioPlayer
.flutter_radio_playing
? Icon(Icons.pause)
: Icon(Icons.play_arrow))
]);
break;
}
...............
So in short, i want to use an image, "pause.png" for Icons.pause and "play.png" for Icons.play_arrow.

Remove that IconButton thing and use this as a child of Future Builder
and the future builder will return this
Image.asset('pause.png'):Image.asset('play.png')

the icon is of type Widget so you can pass for example Image.asset([path to asset]) instead Icon()

here is the example
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
// replace Icon button to this custom button and wrap with Inkwell
children: <Widget>[
InkWell(
onTap: () async {
print("button press data: " +
snapshot.data.toString());
await _flutterRadioPlayer.playOrPause();
},
child : snapshot.data ==
FlutterRadioPlayer
.flutter_radio_playing
? Image.asset("image path")
: Image.asset("image path "))
]);
break;
}

Related

Flutter 2 second shows error when page load and ater 2 secons successfully shows

Hello Any One Flutter Expert here ?? plz help meee...what i want to make is Like Facebook photo viewer when user slides images and check is this like or not same i want in my code...
i made my code in that i come from listing page and when i tap on listing i can see full screen image.. and i Can slide(Scroll) images...
BUTTT when i comes first time on this screen which i code it show me some bugs on screen for 3,4 seconds...after that i can see the image plz help mee and show my error
Future<PhotoDetail> pagedetail() async {
sharedPreferences = await SharedPreferences.getInstance();
Map data = {
"AccessToken": sharedPreferences.getString("AccessToken"),
"CustomerId": sharedPreferences.getInt("CustomerId"),
"ImageId": indexx == null ? widget.images[widget.currentindex].photoId : indexx
};
print(data);
final http.Response response = await http.post(
Constants.CUSTOMER_WEBSERVICE_URL + "/photo/detail",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data),
);
var jsonResponse = json.decode(response.body);
if (response.statusCode == 200) {
print("Response status : ${response.statusCode}");
print("Response status : ${response.body}");
isLike = jsonResponse["IsLike"]; //here i saving value when api is run
print("iSLiked Value:" +isLike.toString()); // value is printing here
return PhotoDetail.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load data');
}
}
Future<PhotoDetail> _photoDetail;
#override
void initState() {
_photoDetail = pagedetail();
setState(() {
pagedetail(); //here is my api run when page is load
});
super.initState();
}
void pageChange(int index){ //this method is when i scroll page
setState(() {
pagedetail(); // api is call again and again
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
body: Stack(
children: <Widget>[
Container(
child:
Center(
child: PhotoViewGallery.builder(
itemCount: widget.images.length,
builder: (BuildContext context , int index) {
return PhotoViewGalleryPageOptions(
imageProvider:
NetworkImage(widget.images[index].photoPreviewImagePath),
maxScale: PhotoViewComputedScale.covered * 1.8,
minScale: PhotoViewComputedScale.contained * 1.0,
);
},
pageController: _pageController,
enableRotation: false,
scrollDirection: Axis.horizontal,
onPageChanged: pageChange,
loadingBuilder: (BuildContext context , ImageChunkEvent event){
return Center(child: CircularProgressIndicator(),);
},
)
)
),
Positioned(
bottom: 10,
left: 30,
right: 30,
child: (_photoDetail == null) ? Text("error")
: FutureBuilder<PhotoDetail>(
future: _photoDetail,
// ignore: missing_return
builder: (context , snapshot){
int like = snapshot.data.isLike;
int Slection = snapshot.data.selectedCount;
print("like ?????:" +like.toString());
print("Selection ????? :" + Slection.toString());
if (snapshot.hasData){
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
child: InkWell(
Likes();
Fluttertoast.showToast(
msg: "Liked",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Color(0xfff58634),
textColor: Colors.white,
fontSize: 16.0
);
},
child: Icon(Icons.thumb_up,size: 20,color: like == 1 ? Color(0xfff58634) : Colors.white),
),
),
InkWell(
child: Icon(Icons.comment,size: 20,color: Colors.white),
),
InkWell(
onTap: (){
_onShare();
},
child: Icon(Icons.share,size: 20,color: Colors.white,),
),
InkWell(
onTap: (){},
child: Icon(Icons.photo_album,size: 20,color: Slection == 0 ? Colors.white : Color(0xfff58634)),
),
InkWell(
onTap: (){
setState(() {
viewwholike();
});
},
child: Icon(Icons.card_giftcard,size: 20,color:
Colors.white,),
),
]
);
}
else {
Text("error");
}
},
),
),
],
),
);
}
ERROR::════════ Exception caught by widgets library
═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building
FutureBuilder<PhotoDetail>(dirty, state:
_FutureBuilderState<PhotoDetail>#ef81b):
The getter 'isLike' was called on null.
Receiver: null
Tried calling: isLike
The relevant error-causing widget was:
FutureBuilder<PhotoDetail>
file:///C:/Users/Hello%20Devloper/AndroidStudioProjects/
September/PhotoGranth-
App/lib/CampaignSinglePhotos.dart:400:15
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _CampaignSinglePhotosState.build.<anonymous closure>
(package:photogranth2020/CampaignSinglePhotos.dart:404:42)
#2 _FutureBuilderState.build
(package:flutter/src/widgets/async.dart:732:55)
#3 StatefulElement.build
(package:flutter/src/widgets/framework.dart:4619:28)
#4 ComponentElement.performRebuild
(package:flutter/src/widgets/framework.dart:4502:15)
Flutter tells you that data is not ready when you test snapshot.data.isLike.
You should test always at the beginning if snapshot.hasData, only after that you can make all you want.
Otherwise, if snapshot.hasData is false, simply return CircularProgressIndicator() .

Flutter: What kind of parameter type can have the argument type 'Image Function(dynamic)' assigned to it?

I'm just trying to load an image. I'm using the beta channel with web support. Flutter 1.19.0-4.3.pre. Dart 2.9.0
This is my pubspec:
flutter:
uses-material-design: true
assets:
- assets/
And this is my main.dart;
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(image: AssetImage('assets/logo.png')),
] < Widget > [
Text('Find happy, temporary, homes for your pets'),
],
),
),
);
}
}
Which I just copy/pasted from the documentation on the Flutter website. Where am I going wrong?
You don't have to have two arrays in a single <Widget>[] Column Class. I can see that you have done this:
<Widget>[
Image(image: AssetImage('assets/logo.png')),
] < Widget > [
Text('Find happy, temporary, homes for your pets'),
],
Which is indeed wrong. What a normal Column() accepts is like this. [To read more about Column class, please click here]
Column(
children: <Widget>[
// You multiple widget goes here not in multiple arrays
Widget1
Widget2
...
]
)
So to correct your code, you should do something like this, else, you have done correct in respect of assets
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
// One single array keeps your multiple widgets
children: <Widget>[
Image(image: AssetImage('assets/logo.png')),
Text('Find happy, temporary, homes for your pets'),
]
)
)
);
}
}
Let me know, if that works for you. Happy learning :)
Make sure your pubspec.yaml file's indentations are correct:
flutter:
assets:
- assets/
And then for your main.dart I think you don't need the Widget Builder. So your main.dart should look like this:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(image: AssetImage('assets/logo.png'),
],
),
),
),
);
}
}

How to get the number of data that are retrieving through response.body?

How can I get the number of data that are retrieving through response.body?
I tried many methods including below one to get that number. But non of them worked out pretty well.
var convertJsonToData = json.decode(response.body);
data = convertJsonToData;
data.forEach((element) => touristCount++);
The variable touristCount is declared and initialized to 0 at the beginning of this dart file.
Here are my codes.
AdminMenu.dart
String apiurl = "http://10.0.2.2:8000/api/retrieveTourists/";
List data;
var touristCount = 0;
class _AdminMenuState extends State<AdminMenu> {
#override
// var touristCount = 2;
// _AdminMenuState({this.touristCount});
void initState() {
super.initState();
this.getTouristCount(context);
}
void getTouristCount(BuildContext context) async {
var response = await http
.get(Uri.encodeFull(apiurl), headers: {"Accept": "application/json"});
if (this.mounted) {
setState(() {
var convertJsonToData = json.decode(response.body);
data = convertJsonToData;
data.forEach((element) => touristCount++);
});
}
}
..................
..................
....................
AuthController.php
public function retrieveTourists(){
$user = tourists::all();
return response()->json($user);
}
api.php
Route::get('/retrieveTourists','Api\AuthController#retrieveTourists');
All I want is to display the count at "Text" here.
Widget buttonSection1 = Container(
padding: const EdgeInsets.only(top: 30),
decoration: BoxDecoration(
border: Border.all(width: 5, color: Colors.black38),
borderRadius: const BorderRadius.all(const Radius.circular(8)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildButtonColumn(color, Icons.people, 'Guides'),
Text(touristCount.toString()), <----------------------------------- Display the count???
],
),
);
Can someone help me with this? :)
If your incoming data is an array, you can use the length property to get the number of data, like this:
if (this.mounted) {
setState(() {
var convertJsonToData = json.decode(response.body);
touristCount = convertJsonToData.length
});
}
I found a way to do that! We can get this thing done by passing the touristCount variable as a parameter to the buttonSection1 widget
Widget buttonSection1(int num_guides){
return Container(
padding: const EdgeInsets.only(top: 30),
decoration: BoxDecoration(
border: Border.all(width: 5, color: Colors.black38),
borderRadius: const BorderRadius.all(const Radius.circular(8)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildButtonColumn(color, Icons.people, 'Guides'),
Text(num_guides.toString()),
],
),
);
}
Calling the widget in build widget
Widget build(BuildContext context) {
return Container(
child: Scaffold(
appBar: AppBar(
leading: Icon(Icons.menu),
title: Text("Admin Menu"),
backgroundColor: Colors.indigo,
actions: <Widget>[
IconButton(icon: Icon(Icons.person)),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
buttonSection1(touristCount),
.....................
.....................

Flutter: "(path): must not be null" on conditional file checks

I am trying to have a background to my application that either the user has chosen previously, or to use a default image if no file is found.
The code is very simple:
decoration: BoxDecoration(
color: Colors.blueAccent,
image: DecorationImage(
image: File(customImageFile).existsSync() ? FileImage(File(customImageFile)) : backgroundImage,
fit: BoxFit.fill,
),
),
The application crashes on the conditional line, saying that (path): Must not be null. I have tried many ways to get around this, but what I am specifically saying there is "if the file path is null, don't use it. Use this image I made earlier for you". But then it gets upset anyway.
Is there another way I can achieve the intended result here?
Edit:
As requested by #Vikas, more complete sample of code involved:
ImageProvider backgroundImage;
String themeLoader = 'blueTheme';
String customImageFile;
// Declaration
void initState() {
_loadThemeSettings();
super.initState();
}
// Initialisation
_loadThemeSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
themeLoader = prefs.getString('themeColour' ?? 'blueTheme');
customImageFile = prefs.getString('customImageFile' ?? 'empty')
if (customImageFile != null) {
if(File(customImageFile).existsSync()) {
prefs.setString('customImageFile', customImageFile);
} else {
print('Path not valid');
}
} else {
print('customImageFile is NULL');
}
if (themeLoader != null) {
switch (themeLoader) {
case 'blueTheme':
{
colorBloc.changeColor('blueTheme');
setState(() {
backgroundImage = ExactAssetImage('lib/images/bg_blue_new.jpg');
buttonTheme = AppState.blueTheme;
}
}
break;
} else {
print('Theme loader was NULL');
}
}
}
}
// Loading previously selected themes at run time. There are several colours here in the case statement, but they are all identical and you get the idea.
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _exitApp(context),
child: Scaffold(
body: SafeArea(
child: BlocProvider<ColorBloc>(
bloc: colorBloc,
child: Container(
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Colors.blueAccent,
image: DecorationImage(
image: (customImageFile != null && File(customImageFile).existsSync()) ? FileImage(File(customImageFile)) : backgroundImage,
fit: BoxFit.fill,
),
),
// that's where it sits, everything else works fine. The rest of the build method is not relevant to this issue, and is working, but here it is anyway:
child: SafeArea(
child: Stack(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
themesVisible == true
? SizedBox()
: buttonRow(),
SizedBox(
height: 20,
),
],
),
Padding(
padding: EdgeInsets.all(15),
child: topMenuRow(),
),
],
),
),
),
BlocProvider<CustomToggleBloc>(
bloc: customToggleBloc,
child: Center(
child: Container(
child: themesVisible == true ? singlePlayerThemes(singlePlayerCallbacks: callBacks) : scoreText(),
),
),
),//bloc
],
),
),
),
),
),
);
}

Flutter low framerate performace

I saw linear degradation of framerate UI when I launch speed_dial animation plugin. The problem appear when I add sharedpref function here:
#override
Widget build(BuildContext context) {
sharedpref_function();
return Scaffold(
to listen a saved value, even If the sharedpref is empty I have this degradation.
After 10min whithout doing nothing before, I measure 1120ms/frame when I call _renderSpeedDial
Here is the full code :
bool _dialVisible = true;
Color _speedDial = Colors.pink;
sharedpref_function() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
}
);
}
_renderSpeedDial() {
return SpeedDial(
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 22.0),
backgroundColor: _speedDial,
// child: Icon(Icons.add),
/* onOpen: () => print('OPENING DIAL'),
onClose: () => print('DIAL CLOSED'),*/
visible: _dialVisible,
curve: Curves.bounceIn,
children: [
SpeedDialChild(
child: Icon(Icons.fullscreen_exit, color: Colors.white),
backgroundColor: Color(0xffa088df),
onTap: () {
setState(() {
});
},
label: '1',
labelStyle: TextStyle(fontWeight: FontWeight.w500,color: Colors.white),
labelBackgroundColor:Color(0xffa088df),
),
],
);
}
#override
Widget build(BuildContext context) {
sharedpref_function(); // here the sharedpref I use to listen saved value
return Scaffold(
body: Stack(
children: <Widget>[
Padding
(
padding: const EdgeInsets.only(right:10.0, bottom:10.0),
child:
_renderSpeedDial(),
),
],
)
);
}
}
Your sharedpref_function() method is being called inside your build method. That's not recommended at all because it will be called on every frame the UI needs to be rebuild and your code, having an animation there, will be called at 60fps (on every frame).
Move your method inside initState or didChangeDependencies (there're even more methods that get called once or a few times like didChangeDependencies).
When you need to update values, you could do it inside an onTap gesture and that's it.
Also, test your app in --release (release mode) to truly test the speed of your app.

Resources