Flutter How to cause a new gesture - flutter

I have a listview which has Slideable
I want a longPress gesture to activate a Slideable Action.
I can get a longpress message, but I do not know what to do to cause the sliding action to work.
This is a custom Tile Widget I need to edit.
This is what it looks like when I swipe.
I want the same thing to happen when I release the longpress
Code is below:
class BookmarkListTile extends StatelessWidget {
// final BookmarkPageViewModel bookmarkViewmodel;
// final int index;
const BookmarkListTile(
{Key? key, required this.bookmark, this.onTap, this.onDelete})
: super(key: key);
final Bookmark bookmark;
final Function(Bookmark bookmark)? onDelete;
final Function(Bookmark bookmark)? onTap;
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onLongPressUp: () {
print("longpress");
// add code here to cause the Slidable Action to happen
},
child: Slidable(
actionPane: const SlidableDrawerActionPane(),
secondaryActions: [
IconSlideAction(
icon: Icons.delete,
color: Colors.red,
onTap: () {
if (onDelete != null) onDelete!(bookmark);
},
)
],
child: ListTile(
onTap: () {
if (onTap != null) onTap!(bookmark);
},
title: Text(bookmark.note),
subtitle: Text(PaliScript.getScriptOf(
language:
context.read<ScriptLanguageProvider>().currentLanguage,
romanText: bookmark.bookName!)),
trailing: SizedBox(
width: 100,
child: Row(
children: [
Text('${AppLocalizations.of(context)!.page} -'),
Expanded(
child: Text(
'${bookmark.pageNumber}',
textAlign: TextAlign.end,
)),
],
),
),
),
));
}
}

Try maybe this:
Widget build(BuildContext context) {
return Slidable(
actionPane: const SlidableDrawerActionPane(),
secondaryActions: [
IconSlideAction(
icon: Icons.delete,
color: Colors.red,
onTap: () {
if (onDelete != null) onDelete!(bookmark);
},
)
],
child: Builder(builder: (context) =>
GestureDetector(
behavior: HitTestBehavior.translucent,
onLongPress: () {
openSlidable(context);
},
child: ListTile(
onTap: () {
if (onTap != null) onTap!(bookmark);
},
title: Text(bookmark.note),
subtitle: Text(PaliScript.getScriptOf(
language:
context.read<ScriptLanguageProvider>().currentLanguage,
romanText: bookmark.bookName!)),
trailing: SizedBox(
width: 100,
child: Row(
children: [
Text('${AppLocalizations.of(context)!.page} -'),
Expanded(
child: Text(
'${bookmark.pageNumber}',
textAlign: TextAlign.end,
)),
],
),
),
))));
}
void openSlidable(BuildContext context) {
final slidable = Slidable.of(context);
final isClosed = slidable.renderingMode == SlidableRenderingMode.none;
if (isClosed) {
Future.delayed(Duration.zero, () {
if (slidable.mounted) {
slidable.open(actionType: SlideActionType.secondary);
}
});
}
}
This will automatically open your slidable if it was closed. Child of Slidable should be wrapped in Builder in order to work.

Related

How to Change the label of an existing chip in flutter?

I'm using chips in my code when I tap on chip a counter is displayed, I want to update the chip label with when count is added.
Widget returnWidget() {
return InkWell(
child: Chip(
label: Text(temp!),
),
onTap: () {
print(temp);
_showMyDialog();
},
);
}
This is the widget I'm using to add multiple chips.
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
scrollable: false,
title: const Text('Add Count'),
content: Container(
height: 50,
width: 50,
alignment: Alignment.center,
padding: const EdgeInsets.all(3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
AddCount(),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
{
setState(() {
_itemCount = 0;
});
}
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Add'),
onPressed: () {
if(count==0) {
setState((){
temp = temp! + _itemCount.toString();
Text(temp!);
count++;
});
}
print(text);
},
),
],
);
},
);
}
This is the code block which is showing a counter dialog. I want to update chip label on add.
Hello here I have a solution, I did not see more details about your code but here I did a working solution, the variable you want to update should be located inside the classed where is used but you can also use state management or InheritedWidget to update variables globally:
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Example(),
);
}
}
class Example extends StatefulWidget {
const Example({Key? key}) : super(key: key);
#override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
int temp = 0; // declare the variable inside the class you want to update it
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
scrollable: false,
title: const Text('Add Count'),
content: Container(
height: 50,
width: 50,
alignment: Alignment.center,
padding: const EdgeInsets.all(3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
// AddCount(),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Add'),
onPressed: () {
setState((){
temp = temp += 1; // update the chip UI
});
Navigator.of(context).pop();
},
),
],
);
},
);
}
Widget returnWidget() {
return InkWell(
child: Chip(
label: Text("count $temp"), // <-- new change
),
onTap: () {
print(temp);
_showMyDialog();
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red,
body: Center(
child: Container(
margin: const EdgeInsets.all(32),
child: returnWidget(),
),
),
);
}
}

The method 'setState' isn't defined for the type 'NasabahDataTableSource'

I want to use setState method in class "NasabahDataTableSource" but when i use setState in this class cannot work and Error: The method 'setState' isn't defined for the class 'NasabahDataTableSource'.
'NasabahDataTableSource' is from 'package:flutter_auth/screens/Menu/DataNasabah/datanasabah.dart' ('lib/screens/Menu/DataNasabah/datanasabah.dart').
Try correcting the name to the name of an existing method, or defining a method named 'setState'.
setState(() {
^^^^^^^^
This is mystatefullwidget.
class DataNasabah extends StatefulWidget {
#override
_DataNasabahState createState() => _DataNasabahState();
}
class _DataNasabahState extends State<DataNasabah> {
String nama_debitur = '';
List<Nasabah> _nasabah = [];
#override
void initState() {
super.initState();
_loadUserData();
_getNasabah();
}
_loadUserData() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('user'));
if (user != null) {
setState(() {
nama_debitur = user['nama_debitur'];
});
}
}
_getNasabah() {
NasabahService.getUser().then((nasabah) {
if (mounted) {
setState(() {
_nasabah = nasabah;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Data Nasabah'),
backgroundColor: Color(0xff151515),
// automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
child: PaginatedDataTable(
rowsPerPage: 10,
columns: [
DataColumn(
label: Expanded(
child: Text(
'ID Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Nama Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Aksi',
textAlign: TextAlign.center,
)),
),
],
source: NasabahDataTableSource(userData: _nasabah, context: context),
),
),
);
}
}
I want to use setState method in this class.but cann't use.I
comment setState place
class NasabahDataTableSource extends DataTableSource {
BuildContext context;
NasabahDataTableSource({this.context, this.userData});
final List<Nasabah> userData;
#override
DataRow getRow(int index) {
return DataRow.byIndex(
index: index,
cells: [
DataCell(Align(
alignment: Alignment.center,
child: Text(
"${userData[index].id}",
))),
DataCell(Align(
alignment: Alignment.center,
child: Text("${userData[index].nama_debitur}"),
)),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(Icons.navigate_next),
color: Colors.blueAccent,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailNasabah(
nasabah: userData[index],
),
),
);
},
),
IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () {
showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: Text('Hapus Data Nasabah'),
content: Text(
'Apakah anda yakin ingin menghapus data nasabah ini?'),
actions: [
TextButton(
child: Text('Yes'),
onPressed: () {
NasabahService.deleteUser(userData[index].id);
setState(() {
//Cann't use
});
})
],
),
);
},
)
],
),
),
],
);
}
i haven't find that solution.
Please help.
You can not use setState() without StatefulWidget. I suggest you to use Function to pass your action and notify to rebuild UI using setState(). Need little bit modification on your code.
Add Function parameter to your NasabahDataTableSource.
Function onUserDeleted;
Modify your NasabahDataTableSource constructor.
NasabahDataTableSource({required this.context,required this.userData,required this.onUserDeleted}); // modify your constructor
Replace setState by onUserDeleted inside onPressed.
onUserDeleted(); // call onUserDeleted
//setState(() {
//Cann't use
//});
NasabahDataTableSource full code.
class NasabahDataTableSource extends DataTableSource {
BuildContext context;
Function onUserDeleted; // add onUserDeleted function
final List<Nasabah> userData;
NasabahDataTableSource({required this.context,required this.userData,required this.onUserDeleted}); // modify your constructor
#override
DataRow getRow(int index) {
return DataRow.byIndex(
index: index,
cells: [
DataCell(Align(
alignment: Alignment.center,
child: Text(
"${userData[index].id}",
))),
DataCell(Align(
alignment: Alignment.center,
child: Text("${userData[index].nama_debitur}"),
)),
DataCell(
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(Icons.navigate_next),
color: Colors.blueAccent,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailNasabah(
nasabah: userData[index],
),
),
);
},
),
IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () {
showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: Text('Hapus Data Nasabah'),
content: Text(
'Apakah anda yakin ingin menghapus data nasabah ini?'),
actions: [
TextButton(
child: Text('Yes'),
onPressed: () {
NasabahService.deleteUser(userData[index].id);
onUserDeleted(); // call onUserDeleted
//setState(() {
//Cann't use
//});
})
],
),
);
},
)
],
),
),
],
);
}
Modify your DataNasabah source by adding onUserDeleted and call setState
source: NasabahDataTableSource(
userData: _nasabah,
context: context,
onUserDeleted:(){
setState((){}); // add setState
}),
DataNasabah full code.
class DataNasabah extends StatefulWidget {
#override
_DataNasabahState createState() => _DataNasabahState();
}
class _DataNasabahState extends State<DataNasabah> {
String nama_debitur = '';
List<Nasabah> _nasabah = [];
#override
void initState() {
super.initState();
_loadUserData();
_getNasabah();
}
_loadUserData() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('user'));
if (user != null) {
setState(() {
nama_debitur = user['nama_debitur'];
});
}
}
_getNasabah() {
NasabahService.getUser().then((nasabah) {
if (mounted) {
setState(() {
_nasabah = nasabah;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Data Nasabah'),
backgroundColor: Color(0xff151515),
// automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
child: PaginatedDataTable(
rowsPerPage: 10,
columns: [
DataColumn(
label: Expanded(
child: Text(
'ID Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Nama Nasabah',
textAlign: TextAlign.center,
)),
),
DataColumn(
label: Expanded(
child: Text(
'Aksi',
textAlign: TextAlign.center,
)),
),
],
source: NasabahDataTableSource(
userData: _nasabah,
context: context,
onUserDeleted:(){
setState((){}); // add setState
}),
),
),
);
}
}
you cant setstate in NasabahDataTableSource because not extends StatefulWidget. only stateful who can setstate.
but you can change variable without setstate using getx in stateless.

Why isn't Navigator.pop() refreshing data?

Hi guys I'm trying to build an app with flutter, so I have two screens HomeScreen() and RoutineScreen(). The first one is a Scaffold and in the body has a child Widget (a ListView called RoutinesWidget()) with all the routines. And the second one is to create a routine. The thing is, that when I create the routine, I use a button to pop to the HomeScreen() but it doesn't refresh the ListView (I'm guessing that it's because when I use Navigator.pop() it refreshes the Scaffold but not the child Widget maybe?)
HomeScreen() code here:
import 'package:flutter/material.dart';
import 'package:workout_time/constants.dart';
import 'package:workout_time/Widgets/routines_widget.dart';
import 'package:workout_time/Widgets/statistics_widget.dart';
import 'package:workout_time/Screens/settings_screen.dart';
import 'package:workout_time/Screens/routine_screen.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 0;
List<Widget> _views = [
RoutinesWidget(),
StatisticsWidget(),
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kThirdColor,
appBar: AppBar(
leading: Icon(Icons.adb),
title: Text("Workout Time"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => SettingsScreen()))),
],
),
body: _views[_selectedIndex],
floatingActionButton: (_selectedIndex == 1)
? null
: FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoutineScreen(null)));
setState(() {});
},
child: Icon(
Icons.add,
color: kSecondColor,
size: 30.0,
),
elevation: 15.0,
),
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
bottomItems(Icon(Icons.fitness_center_rounded), "Routines"),
bottomItems(Icon(Icons.leaderboard_rounded), "Statistics"),
],
currentIndex: _selectedIndex,
onTap: (int index) => setState(() => _selectedIndex = index),
),
);
}
}
BottomNavigationBarItem bottomItems(Icon icon, String label) {
return BottomNavigationBarItem(
icon: icon,
label: label,
);
}
RoutinesWidget() code here:
import 'package:flutter/material.dart';
import 'package:workout_time/Services/db_crud_service.dart';
import 'package:workout_time/Screens/routine_screen.dart';
import 'package:workout_time/constants.dart';
import 'package:workout_time/Models/routine_model.dart';
class RoutinesWidget extends StatefulWidget {
#override
_RoutinesWidgetState createState() => _RoutinesWidgetState();
}
class _RoutinesWidgetState extends State<RoutinesWidget> {
DBCRUDService helper;
#override
void initState() {
super.initState();
helper = DBCRUDService();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: helper.getRoutines(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Routine routine = Routine.fromMap(snapshot.data[index]);
return Card(
margin: EdgeInsets.all(1.0),
child: ListTile(
leading: CircleAvatar(
child: Text(
routine.name[0],
style: TextStyle(
color: kThirdOppositeColor,
fontWeight: FontWeight.bold),
),
backgroundColor: kAccentColor,
),
title: Text(routine.name),
subtitle: Text(routine.exercises.join(",")),
trailing: IconButton(
icon: Icon(Icons.delete_rounded),
color: Colors.redAccent,
onPressed: () {
setState(() {
helper.deleteRoutine(routine.id);
});
},
),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoutineScreen(routine))),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0)),
color: kSecondColor,
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
RoutineScreen() code here:
import 'package:flutter/material.dart';
import 'package:workout_time/Models/routine_model.dart';
import 'package:workout_time/Widgets/type_card_widget.dart';
import 'package:workout_time/constants.dart';
import 'package:workout_time/Services/db_crud_service.dart';
class RoutineScreen extends StatefulWidget {
final Routine _routine;
RoutineScreen(this._routine);
#override
_RoutineScreenState createState() => _RoutineScreenState();
}
class _RoutineScreenState extends State<RoutineScreen> {
DBCRUDService helper;
final _nameController = TextEditingController();
final _descriptionController = TextEditingController();
bool _type = true;
int _cycles = 1;
int _restBetweenExercises = 15;
int _restBetweenCycles = 60;
#override
void initState() {
super.initState();
helper = DBCRUDService();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
title: widget._routine != null
? Text(widget._routine.name)
: Text("Create your routine"),
actions: [
IconButton(
icon: Icon(Icons.done_rounded),
onPressed: createRoutine,
)
],
bottom: TabBar(
tabs: [
Tab(
text: "Configuration",
),
Tab(
text: "Exercises",
),
],
),
),
body: TabBarView(children: [
//_routine == null ? ConfigurationNewRoutine() : Text("WIDGET N° 1"),
ListView(
children: [
Container(
padding: EdgeInsets.all(15.0),
child: Row(
children: [
Text(
"Name:",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(
width: 40.0,
),
Expanded(
child: TextField(
textAlign: TextAlign.center,
controller: _nameController,
),
),
],
),
),
SizedBox(
height: 20.0,
),
Card(
margin: EdgeInsets.all(15.0),
color: kSecondColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Container(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Text(
"Type",
style: TextStyle(fontSize: 25.0),
),
Row(
children: [
Expanded(
child: TypeCard(
Icons.double_arrow_rounded,
_type == true ? kFirstColor : kThirdColor,
() => setState(() => _type = true),
"Straight set",
),
),
Expanded(
child: TypeCard(
Icons.replay_rounded,
_type == false ? kFirstColor : kThirdColor,
() => setState(() => _type = false),
"Cycle",
),
),
],
),
],
),
),
),
SizedBox(
height: 20.0,
),
Container(
padding: EdgeInsets.all(15.0),
child: Row(
children: [
Text(
"N° cycles:",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(
width: 40.0,
),
Expanded(
child: Text("Hello"),
),
],
),
),
SizedBox(
height: 20.0,
),
],
),
Text("WIDGET N° 2"),
]),
),
);
}
void createRoutine() {
List<String> _exercises = ["1", "2"];
List<String> _types = ["t", "r"];
List<String> _quantities = ["30", "20"];
Routine routine = Routine({
'name': _nameController.text,
'description': "_description",
'type': _type.toString(),
'cycles': 1,
'numberExercises': 2,
'restBetweenExercises': 15,
'restBetweenCycles': 60,
'exercises': _exercises,
'types': _types,
'quantities': _quantities,
});
setState(() {
helper.createRoutine(routine);
Navigator.pop(context);
});
}
}
Any idea what can I do to make it work? Thank you
Make it simple
use Navigator.pop() twice
so that the current class and old class in also removed
from the stack
and then use Navigator.push()
When you push a new Route, the old one still stays in the stack. The new route just overlaps the old one and forms like a layer above the old one. Then when you pop the new route, it will just remove the layer(new route) and the old route will be displayed as it was before.
Now you must be aware the Navigator.push() is an asynchronous method and returns a Future. How it works is basically when you perform a Navigator.push(), it will push the new route and will wait for it to be popped out. Then when the new route is popped, it returns a value to the old one and that when the future callback will be executed.
Hence the solution you are looking for is add a future callback like this after your Navigator.push() :
Navigator.push(context,
MaterialPageRoute(builder: (context) => SettingsScreen())
).then((value){setState(() {});}); /// A callback which is executed after the new route will be popped. In that callback, you simply call a setState and refresh the page.

Pixel overflow when using an Image.File in flutter

I have a column with 2 children, an Image.File and a Row displaying a Flatbutton.Icon. The Image.File causes an overflow, but when I use Expanded on both Image.File and Row the entire body vanishes. How do I avoid both outcomes and just show the intended which is the photo with a flatbutton below it?
Parent
class ProfileHome extends StatefulWidget {
#override
_ProfileHomeState createState() => _ProfileHomeState();
}
class _ProfileHomeState extends State<ProfileHome> {
File _imageFile;
Future<void> _pickImage(ImageSource source) async {
File selected = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = selected;
});
}
void _clear() {
setState(() => _imageFile = null);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text(
'My Profile',
style: TextStyle(fontFamily: 'Anton'),
),
centerTitle: true),
drawer: Drawer(
child: DrawerWidget(),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_imageFile == null) ...[
ProfileList(
uploadbarvalue: _updateUploadBar,
),
] else ...[
ProfilePhoto(
imageFile: _imageFile,
onImageExit: _clear,
)
]
],
),
bottomNavigationBar: (uploadbar)
? BottomAppBar(
shape: CircularNotchedRectangle(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
padding: EdgeInsets.all(50.0),
icon: Icon(
Icons.photo_camera,
size: 50.0,
),
onPressed: () {
_pickImage(ImageSource.camera);
uploadbar = false;
},
),
IconButton(
padding: EdgeInsets.all(50.0),
icon: Icon(
Icons.photo_library,
size: 50.0,
),
onPressed: () {
_pickImage(ImageSource.gallery);
uploadbar = false;
}),
],
),
)
: null,
floatingActionButton: (uploadbar)
? FloatingActionButton(
backgroundColor: Colors.black,
child: Icon(Icons.close),
onPressed: () {
setState(() {
uploadbar = false;
});
})
: null,
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Child
class ProfilePhoto extends StatefulWidget {
File imageFile;
final VoidCallback onImageExit;
final bool uploadbar;
final ValueChanged<bool> uploadbarvalue;
ProfilePhoto(
{Key key,
this.uploadbar,
this.uploadbarvalue,
this.imageFile,
this.onImageExit})
: super(key: key);
#override
_ProfilePhotoState createState() => _ProfilePhotoState();
}
class _ProfilePhotoState extends State<ProfilePhoto> {
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
if (widget.imageFile != null) ...[
Image(image: FileImage(widget.imageFile)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton.icon(
onPressed: () {
_imageFinished();
},
icon: Icon(Icons.clear),
label: Text('Clear'))
],
),
Uploader(
file: widget.imageFile,
)
]
]);
}
}

Refresh part of screen in flutter

EDIT - Complete Code. I added SetState and it didnt refresh.
class ForumPost extends StatefulWidget {
#override
_ForumPostState createState() => new _ForumPostState();
final User user;
final String postID;
final Features features;
ForumPost({Key key, #required this.user, #required this.postID, #required this.features}) : super(key: key);
}
class _ForumPostState extends State<ForumPost> {
List<TabItem> navItems = <TabItem>[
TabItem(icon: Icons.home, title: 'Home'),
TabItem(icon: Icons.help_outline, title: 'Support'),
TabItem(icon: Icons.people, title: 'Contacts'),
TabItem(icon: Icons.chat_bubble, title: 'Forum')
];
List data;
Future<String> getPostsByCategory() async {
var response = await http.post(
Uri.encodeFull("http://url/api/ForumPostByPostID"),
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'PostID' : widget.postID }));
this.setState(() {
data = json.decode(response.body);
}
);
return "Success!";
}
#override void initState() {
this.getPostsByCategory();
}
#override
Widget build(BuildContext context) {
Future forumUpVote(String userid, String postID) async {
final response =
await http.post('http://url/api/ForumUpvote',
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'userid' : userid , 'postID' : widget.postID}));
if (response.statusCode == 204) {
// Call was successful
// Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPost(user: widget.user, postID: widget.postID, features: widget.features)));
setState(() {
});
}
}
return new Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey,
centerTitle: true,
actions: <Widget>[
new IconButton( icon: new Icon(
FontAwesomeIcons.plusCircle,),
tooltip: 'Ask Question',
onPressed: (){
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumAskQuestion( user: widget.user, features: widget.features)));
}
),
new IconButton( icon: new Icon(
FontAwesomeIcons.search,),
tooltip: 'Search Community',
onPressed: (){
print('pressed');
}
)
]
),
bottomNavigationBar: ConvexAppBar.builder(
user: widget.user,
features: widget.features,
count: navItems.length,
backgroundColor: Colors.grey[700],
tabBuilder: (BuildContext context, int index, bool active) {
var navigationItem = navItems[index];
var _color = active ? Colors.white : Colors.white60;
var _icon = active
? navigationItem.activeIcon ?? navigationItem.icon
: navigationItem.icon;
return Container(
color: Colors.transparent,
padding: EdgeInsets.only(bottom: 2),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(_icon, color: _color),
Text(navigationItem.title, style: TextStyle(color: _color, fontSize: 12.0))
],
),
);
},
actionBuilder: (BuildContext context, int index, bool active) {
var _color = active ? Colors.white : Colors.white60;
return Stack(
alignment: Alignment.center,
children: <Widget>[
SizedBox(
width: 60,
height: 60,
child: Container(
decoration:
BoxDecoration(shape: BoxShape.circle, color: _color),
child: Icon(
Icons.chat_bubble,
size: 40,
color: Colors.red[200],
),
),
)
],
);
},
),
body: Container(
decoration: BoxDecoration(
gradient: new LinearGradient(
colors: [Colors.white, Colors.grey],
begin: Alignment.bottomLeft,
end: Alignment.topRight
)
),
child: ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index){
return new Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.beenhere, color: Colors.red, size: 35.0,),
title: new Text(data[index]["Title"],style: new TextStyle(fontSize: 20.0, color: Colors.grey) ),
subtitle: new Text(data[index]["Content"],style: new TextStyle(fontSize: 15.0, color: Colors.grey)),
trailing: new Text(data[index]["FirstName"],style: new TextStyle(fontSize: 15.0, color: Colors.grey)),
isThreeLine: true,
),
ButtonTheme.bar( // make buttons use the appropriate styles for cards
child: ButtonBar(
children: <Widget>[
FlatButton(
padding: EdgeInsets.all(10.0),
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.thumb_up, color: Colors.grey[600]),
Text(data[index]["UpVote"].toString(), style: new TextStyle(color: Colors.grey))
],
),
onPressed: () {
forumUpVote(widget.user.userId, widget.postID);
},
),
FlatButton(
padding: EdgeInsets.all(10.0),
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.question_answer, color: Colors.blue),
Text("Answer", style: new TextStyle(color: Colors.grey))
],
),
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumAnswerQuestion( user: widget.user, postID: widget.postID, posttitle: data[index]["Title"], features: widget.features )));
},
),
FlatButton(
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.info_outline, color: Colors.orangeAccent),
Text(data[index]["AnswerCount"].toString(), style: new TextStyle(color: Colors.grey))
],
),
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPostsDetail( user: widget.user, postID: widget.postID, posttitle: data[index]["Title"], content: data[index]["Content"], features: widget.features )));
},
),
FlatButton(
child: Column( // Replace with a Row for horizontal icon + text
children: <Widget>[
Icon(Icons.flag, color: Colors.red),
Text("Flag", style: new TextStyle(color: Colors.red))
],
),
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPostsDetail( user: widget.user, postID: widget.postID, posttitle: data[index]["Title"], content: data[index]["Content"], features: widget.features )));
},
),
],
),
),
]
),
);
},
)
)
);
}
}
We have a forum written in flutter and an upvote post function that calls a web api via http. We need the icon with the count of upvotes to refresh but not the entire screen. How is this done in flutter? We used to achieve this via AJAX in web pages.
Here is the code for the upvote icon
children: <Widget>[
Icon(Icons.thumb_up, color: Colors.green),
Text(data[index]["UpVote"].toString(), style: new TextStyle(color: Colors.grey))
],
Code for HTTP Call
Future forumUpVote(String userid, String postID) async {
final response =
await http.post('http://url/api/ForumUpvote',
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'userid' : userid , 'postID' : widget.postID}));
if (response.statusCode == 204) {
// Call was successful
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new ForumPost(user: widget.user, postID: widget.postID, features: widget.features)));
}
}
When the response is successful it sends them back to the same screen which is why the entire screen refreshes. So Im guessing that we need to setstate() or something along those lines. Im not sure how to fix this.
Can you create a separate stateful widget that is referenced in your current widget which has the upvote button along with the upvote counter?
Then when it is pressed you only call the setState() method within that child widget. This will only refresh that widget and not the whole page.
In below code I made two widgets. The first (called "mainWidget") is the one that you do not want to refresh and it references the second widget (called "refreshingWidget"). They both hold state but only the refreshing widget is updated when you call setState().
class mainWidget extends StatefulWidget {
#override
_mainWidgetState createState() => _mainWidgetState();
}
class _mainWidgetState extends State<mainWidget> {
#override
Widget build(BuildContext context) {
print("Main widget is refreshing");
return new refreshingWidget();
}
}
class refreshingWidget extends StatefulWidget {
#override
_refreshingWidgetState createState() => _refreshingWidgetState();
}
class _refreshingWidgetState extends State<refreshingWidget> {
#override
Widget build(BuildContext context) {
print("Refreshing widget is refreshing.");
return RaisedButton(
onPressed: () {
setState(() {});
},
child: Text("Press to refresh this widget"));
}
}