gpt4 book ai didi

flutter - Flutter-如何在调用某个操作按钮时重新加载整个页面(再次以其初始化状态重新加载小部件)?

转载 作者:行者123 更新时间:2023-12-03 03:51:24 28 4
gpt4 key购买 nike

我有一个包含自定义标签 View 的有状态窗口小部件。
在小部件初始化时,将从Firestore中获取类别数据(此处为All,Science,Trending,Health&Fitness),并相应地将相应的小部件添加到选项卡 View 中。
要添加新类别,可以从最后一个选项卡(此处为'+')中进行选择。在相应的小部件内,可以选择自己感兴趣的类别。
在“添加类别”按钮的点击上,我将选定的类别添加到Firestore中,但是此后,我想重新加载小部件并加载其initstate(因为在initstate中获取了类别数据)。
请问somone请解释一下我如何在这里实现相同目标?

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_advanced_networkimage/provider.dart';
import 'package:flutter_advanced_networkimage/transition.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:journey_togather/pages/home.dart';
import 'package:journey_togather/pages/invite_friends.dart';
import 'package:journey_togather/pages/journey/create_journey.dart';
import 'package:journey_togather/pages/journey/create_paid_journey.dart';
import 'package:journey_togather/pages/journey/journey_home.dart';
import 'package:journey_togather/pages/locator.dart';
import 'package:journey_togather/services/analytics.dart';
import 'package:journey_togather/settings/appbuilder.dart';
import 'package:journey_togather/settings/sizeconfig.dart';
import 'package:journey_togather/settings/textstyle.dart';
import 'package:journey_togather/widgets/all_user_journey.dart';
import 'package:journey_togather/widgets/pillButton.dart';
import 'package:journey_togather/widgets/progress.dart';
import 'package:uuid/uuid.dart';

class ExploreFeed extends StatefulWidget {
@override
_ExploreFeedState createState() => _ExploreFeedState();
}

class _ExploreFeedState extends State<ExploreFeed>
with TickerProviderStateMixin {
bool isLoading = false;

final AnalyticsService _analyticsService = locator<AnalyticsService>();
TabController tabController;

final _scaffoldKey = GlobalKey<ScaffoldState>();

// this will control the button clicks and tab changing
TabController _controller;
// this will control the animation when a button changes from an off state to an on state
AnimationController _animationControllerOn;

// this will control the animation when a button changes from an on state to an off state
AnimationController _animationControllerOff;

// this will give the background color values of a button when it changes to an on state
Animation _colorTweenBackgroundOn;
Animation _colorTweenBackgroundOff;

// this will give the foreground color values of a button when it changes to an on state
Animation _colorTweenForegroundOn;
Animation _colorTweenForegroundOff;

// when swiping, the _controller.index value only changes after the animation, therefore, we need this to trigger the animations and save the current index
int _currentIndex = 0;

// saves the previous active tab
int _prevControllerIndex = 0;

// saves the value of the tab animation. For example, if one is between the 1st and the 2nd tab, this value will be 0.5
double _aniValue = 0.0;

// saves the previous value of the tab animation. It's used to figure the direction of the animation
double _prevAniValue = 0.0;

List<dynamic> _userInterestCategory = ['All'];
List<dynamic> _userInterestCategoryId = ['All'];
List<Widget> _interestFeedBuild = [];

//saves the newly added interest data of a user from add category tab
List _interestDataId = [];
List _interestDataName = [];

// store the pill buttons for categories in add category page
List<Widget> buttons;

Color _foregroundOn = Colors.white;
Color _foregroundOff = Colors.grey;

// active button's background color
Color _backgroundOn = Colors.green;
// Color _backgroundOff = Colors.black;
Color _backgroundOff = Colors.grey.withOpacity(0.1);

// scroll controller for the TabBar
ScrollController _tabScrollController = new ScrollController();

// this will save the keys for each Tab in the Tab Bar, so we can retrieve their position and size for the scroll controller
List _keys = [];

bool _buttonTap = false;
// ScrollController _scrollController = ScrollController();

@override
void initState() {
setState(() {
isLoading = true;
});
_initialiseData();
// WidgetsBinding.instance.addPostFrameCallback(_initialiseData());
super.initState();
}

_initialiseData()async{
_getInterestData().whenComplete(() {
for (int index = 0; index < _userInterestCategory.length; index++) {
// create a GlobalKey for each Tab
_keys.add(new GlobalKey());
}

// this creates the controller with 6 tabs (in our case)
_controller =
TabController(vsync: this, length: _userInterestCategory.length);
// this will execute the function every time there's a swipe animation
_controller.animation.addListener(_handleTabAnimation);
// this will execute the function every time the _controller.index value changes
_controller.addListener(_handleTabChange);

_animationControllerOff = AnimationController(
vsync: this, duration: Duration(milliseconds: 75));
// so the inactive buttons start in their "final" state (color)
_animationControllerOff.value = 1.0;
_colorTweenBackgroundOff =
ColorTween(begin: _backgroundOn, end: _backgroundOff)
.animate(_animationControllerOff);
_colorTweenForegroundOff =
ColorTween(begin: _foregroundOn, end: _foregroundOff)
.animate(_animationControllerOff);

_animationControllerOn = AnimationController(
vsync: this, duration: Duration(milliseconds: 150));
// so the inactive buttons start in their "final" state (color)
_animationControllerOn.value = 1.0;
_colorTweenBackgroundOn =
ColorTween(begin: _backgroundOff, end: _backgroundOn)
.animate(_animationControllerOn);
_colorTweenForegroundOn =
ColorTween(begin: _foregroundOff, end: _foregroundOn)
.animate(_animationControllerOn);

_userInterestCategoryId.forEach((element) {
if (element != '+') {
_interestFeedBuild.add(
BuildInterestFeed(
categoryId: element,
),
);
} else {
buildButton();
_interestFeedBuild.add(
_buildAddInterest(),
);
}
});
setState(() {
isLoading = false;
});
});
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

_getInterestData() async {
DocumentSnapshot _doc =
await userInterestsRef.document(currentUser.id).get();
List _interestsFetched = _doc.data['categories'];
_interestsFetched = _interestsFetched.toSet().toList();
Map _userInterestData = {};
for (var val in _interestsFetched) {
Map _filteredData =
globalInterest.firstWhere((element) => element['categoryId'] == val);
_userInterestData[_filteredData['categoryId']] =
(_filteredData['categoryName']);
}
setState(() {
_userInterestCategory =
_userInterestCategory + _userInterestData.values.toList() + ['+'];
_userInterestCategoryId =
_userInterestCategoryId + _userInterestData.keys.toList() + ['+'];
});
}

//tab bar functions
// runs during the switching tabs animation
_handleTabAnimation() {
// gets the value of the animation. For example, if one is between the 1st and the 2nd tab, this value will be 0.5
_aniValue = _controller.animation.value;

// if the button wasn't pressed, which means the user is swiping, and the amount swipped is less than 1 (this means that we're swiping through neighbor Tab Views)
if (!_buttonTap && ((_aniValue - _prevAniValue).abs() < 1)) {
// set the current tab index
_setCurrentIndex(_aniValue.round());
}

// save the previous Animation Value
_prevAniValue = _aniValue;
}

// runs when the displayed tab changes
_handleTabChange() {
// if a button was tapped, change the current index
if (_buttonTap) _setCurrentIndex(_controller.index);

// this resets the button tap
if ((_controller.index == _prevControllerIndex) ||
(_controller.index == _aniValue.round())) _buttonTap = false;

// save the previous controller index
_prevControllerIndex = _controller.index;
}

_setCurrentIndex(int index) {
// if we're actually changing the index
if (index != _currentIndex) {
setState(() {
// change the index
_currentIndex = index;
});

// trigger the button animation
_triggerAnimation();
// scroll the TabBar to the correct position (if we have a scrollable bar)
_scrollTo(index);
}
}

_triggerAnimation() {
// reset the animations so they're ready to go
_animationControllerOn.reset();
_animationControllerOff.reset();

// run the animations!
_animationControllerOn.forward();
_animationControllerOff.forward();
}

_scrollTo(int index) {
// get the screen width. This is used to check if we have an element off screen

double screenWidth = MediaQuery.of(context).size.width;

// get the button we want to scroll to

RenderBox renderBox = _keys[index].currentContext.findRenderObject();
// get its size
double size = renderBox.size.width;
// and position
double position = renderBox.localToGlobal(Offset.zero).dx;

// this is how much the button is away from the center of the screen and how much we must scroll to get it into place
double offset = (position + size / 2) - screenWidth / 2;

// if the button is to the left of the middle
if (offset < 0) {
// get the first button
renderBox = index-1 < 0 ? _keys[0].currentContext.findRenderObject() : _keys[index - 1].currentContext.findRenderObject();
// get the position of the first button of the TabBar
position = renderBox.localToGlobal(Offset.zero).dx;

// if the offset pulls the first button away from the left side, we limit that movement so the first button is stuck to the left side
if (position > offset) offset = position;
} else {
// if the button is to the right of the middle

// get the last button
renderBox = index+1 == _userInterestCategory.length ? _keys[_userInterestCategory.length-1]
.currentContext
.findRenderObject(): _keys[index + 1]
.currentContext
.findRenderObject();
// get its position
position = renderBox.localToGlobal(Offset.zero).dx;
// and size
size = renderBox.size.width;

// if the last button doesn't reach the right side, use it's right side as the limit of the screen for the TabBar
if (position + size < screenWidth) screenWidth = position + size;

// if the offset pulls the last button away from the right side limit, we reduce that movement so the last button is stuck to the right side limit
if (position + size - offset < screenWidth) {
offset = position + size - screenWidth;
}
}

// scroll the calculated amount
_tabScrollController.animateTo(offset + _tabScrollController.offset,
duration: new Duration(milliseconds: 150), curve: Curves.easeInOut);
}

_getBackgroundColor(int index) {
if (index == _currentIndex) {
// if it's active button
return _colorTweenBackgroundOn.value;
} else if (index == _prevControllerIndex) {
// if it's the previous active button
return _colorTweenBackgroundOff.value;
} else {
// if the button is inactive
return _backgroundOff;
}
}

_getForegroundColor(int index) {
// the same as the above
if (index == _currentIndex) {
return _colorTweenForegroundOn.value;
} else if (index == _prevControllerIndex) {
return _colorTweenForegroundOff.value;
} else {
return _foregroundOff;
}
}

callback(Map data) {
if (data['method'] == 'delete') {
setState(() {
_interestDataId.removeWhere((element) => element == data['id']);
_interestDataName.removeWhere((element) => element == data['name']);
});
} else {
setState(() {
_interestDataId.add(data['id']);
_interestDataName.add(data['name']);
});
}
}

addInterest(context) async {
if(_interestDataId.length > 0 && _interestDataName.length > 0) {
await userInterestsRef
.document(currentUser.id)
.updateData({'categories': FieldValue.arrayUnion(_interestDataId)});


Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return Home();
},
),
);

}
else{
SnackBar snackbar = SnackBar(
content: Text("Please select atleast 1 interest before submitting"),
);
_scaffoldKey.currentState.showSnackBar(snackbar);
}

}

buildButton() {
List<Widget> _buttons = [];
globalInterest.forEach((element) {
if (_userInterestCategoryId.contains(element['categoryId'])) {
} else {
_buttons.add(PillButton(
interestId: element['categoryId'],
interestTitle: element['categoryName'],
callback: callback,
));
}
});
setState(() {
buttons = _buttons;
});
}

Widget _buildAddInterest() {
return Scaffold(
bottomNavigationBar: buttons.length != 0 ?
Container(
margin: EdgeInsets.only(bottom: 16.0),
padding: EdgeInsets.symmetric(horizontal: 16.0),
height: 40,
child: FlatButton(
onPressed: () => addInterest(context),
color: Colors.black,
child: Text(
'Add category',
style: Theme.of(context)
.textTheme
.subtitle2
.copyWith(color: Theme.of(context).primaryColor),
),
),
) : Container(),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: buttons.length != 0
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Wrap(
spacing: 12.0,
children: buttons,
),
],
)
: Center(
child: Text(
'Voila! You\'ve selected all the available interests.',
style: Theme.of(context).textTheme.subhead.copyWith(
color:
Theme.of(context).primaryColorDark.withOpacity(0.40),),
// Colors.black,)
),
),
),
);
}

@override
Widget build(BuildContext context) {
return isLoading
? circularProgress(context)
: AppBuilder(
builder: (context){
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Theme.of(context).primaryColor,
elevation: 0,
title: IconButton(
iconSize: SizeConfig.safeBlockHorizontal * 21,
icon: Image.asset(
Theme.of(context).brightness == Brightness.light
? 'assets/images/logo.png'
: 'assets/images/journey_exploreFeed_dark.png',
),
),
titleSpacing: 8.0,
actions: <Widget>[
IconButton(
padding: EdgeInsets.only(right: 24),
icon: new Image.asset(
Theme.of(context).brightness == Brightness.light
? 'assets/icons/create_journey_black.png'
: 'assets/icons/create_journey_white.png'),
onPressed: () {
_analyticsService.logCreateJourneyExploreFeed();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CreateJourney()),
);
},
),
IconButton(
padding: EdgeInsets.only(right: 16),
icon:
new Image.asset('assets/icons/invite_friends_icon.png'),
onPressed: () {
_analyticsService.logShareApp();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InviteFriends()),
);
},
),
]),
backgroundColor: Colors.transparent,
body: Column(children: <Widget>[
// this is the TabBar
Container(
height: 52.0,
color: Theme.of(context).primaryColor,
// this generates our tabs buttons
child: ListView.builder(
// this gives the TabBar a bounce effect when scrolling farther than it's size
physics: BouncingScrollPhysics(),
controller: _tabScrollController,
// make the list horizontal
scrollDirection: Axis.horizontal,
// number of tabs
itemCount: _userInterestCategory.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
// each button's key
key: _keys[index],
// padding for the buttons
padding: EdgeInsets.fromLTRB(8.0, 4.0, 0.0, 8.0),
child: ButtonTheme(
child: AnimatedBuilder(
animation: _colorTweenBackgroundOn,
builder: (context, child) => FlatButton(
// get the color of the button's background (dependent of its state)
color: _getBackgroundColor(index),
padding:
EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
// make the button a rectangle with round corners
shape: RoundedRectangleBorder(
borderRadius:
new BorderRadius.circular(24.0)),
onPressed: () {
setState(() {
_buttonTap = true;
// trigger the controller to change between Tab Views
_controller.animateTo(index);
// set the current index
_setCurrentIndex(index);
// scroll to the tapped button (needed if we tap the active button and it's not on its position)
_scrollTo(index);
});
},
child: index !=
_userInterestCategory.length - 1
? Text(
// get the icon
_userInterestCategory[index],
// get the color of the icon (dependent of its state)
style: (TextStyle(
color: _getForegroundColor(index),
)),
)
: Icon(
Icons.add,
color: _getForegroundColor(index),
)),
)));
})),
Flexible(
// this will host our Tab Views
child: TabBarView(
// and it is controlled by the controller
controller: _controller,
children: _interestFeedBuild,
)),
]));
},
);
}
}

class BuildInterestFeed extends StatefulWidget {
final String categoryId;

BuildInterestFeed({this.categoryId});
@override
_BuildInterestFeedState createState() => _BuildInterestFeedState();
}

class _BuildInterestFeedState extends State<BuildInterestFeed>
with AutomaticKeepAliveClientMixin {
bool isLoading = false;
List<Journey> journeys = [];
final AnalyticsService _analyticsService = locator<AnalyticsService>();
String docId = Uuid().v4();
List<DocumentSnapshot> journeysFetched = []; // stores fetched products
bool hasMore = true; // flag for more products available or not
int documentLimit = 10; // documents to be fetched per request
DocumentSnapshot
lastDocument; // flag for last document from where next 10 records to be fetched
ScrollController _verticalScrollController = ScrollController();

@override
void initState() {
super.initState();

if (widget.categoryId != '+') {
_getExploreFeedData();
_verticalScrollController.addListener(() {
double maxScroll = _verticalScrollController.position.maxScrollExtent;
double currentScroll = _verticalScrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.10;
if (maxScroll - currentScroll <= delta) {
_getExploreFeedData();
}
});
}
}

_getExploreFeedData() async {
if (!hasMore) {
print('No More Journeys');
return;
}
if (isLoading) {
return;
}
setState(() {
isLoading = true;
});
if (widget.categoryId == 'All') {
await buildAllDataFeed();
} else {
QuerySnapshot querySnapshot;
if (lastDocument == null) {
querySnapshot = await journeyRef
.orderBy('createdAt', descending: true)
.where('category', arrayContains: widget.categoryId)
.limit(documentLimit)
.getDocuments();
} else {
querySnapshot = await journeyRef
.orderBy('createdAt', descending: true)
.where('category', arrayContains: widget.categoryId)
.startAfterDocument(lastDocument)
.limit(documentLimit)
.getDocuments();
}
if (querySnapshot.documents.length != 0) {
if (querySnapshot.documents.length < documentLimit) {
hasMore = false;
}
if (querySnapshot.documents.length != 0) {
lastDocument =
querySnapshot.documents[querySnapshot.documents.length - 1];
} else {
lastDocument = null;
}
journeysFetched.addAll(querySnapshot.documents);
}
}
setState(() {
isLoading = false;
});
}

buildAllDataFeed() async {
QuerySnapshot querySnapshot;
if (lastDocument == null) {
querySnapshot = await journeyRef
.orderBy('createdAt', descending: true)
.limit(documentLimit)
.getDocuments();
} else {
querySnapshot = await journeyRef
.orderBy('createdAt', descending: true)
.startAfterDocument(lastDocument)
.limit(documentLimit)
.getDocuments();
}
if (querySnapshot.documents.length < documentLimit) {
hasMore = false;
}
if (querySnapshot.documents.length != 0) {
lastDocument =
querySnapshot.documents[querySnapshot.documents.length - 1];
} else {
lastDocument = null;
}
// lastDocument = querySnapshot.documents[querySnapshot.documents.length - 1];
journeysFetched.addAll(querySnapshot.documents);
}

addInterestData({tags}) async{
userInterestsRef.document(currentUser.id).updateData({
'tags': FieldValue.arrayUnion(tags),
});
}

@override
bool get wantKeepAlive => true;

@override
Widget build(BuildContext context) {
super.build(context);
return
RefreshIndicator(
onRefresh: () => _getExploreFeedData(),
child:
Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(children: [
Expanded(
child: journeysFetched.length == 0
? Center(
child: Text(
'There\'s nothing new here right now',
style: Theme.of(context).textTheme.subhead.copyWith(
color: Theme.of(context)
.primaryColorDark
.withOpacity(0.40)),
),
)
: StaggeredGridView.countBuilder(
controller: _verticalScrollController,
crossAxisCount: 2,
itemCount: journeysFetched.length,
itemBuilder: (BuildContext context, int index) {
Map journeyData = journeysFetched.elementAt(index).data;
String journeyId =
journeysFetched.elementAt(index).documentID;
return GestureDetector(
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TransitionToImage(
transitionType: TransitionType.fade,
borderRadius: BorderRadius.circular(8.0),
loadingWidget: Container(
height: 242,
decoration: (BoxDecoration(
borderRadius:
BorderRadius.circular(8.0),
color: Theme.of(context)
.primaryColorLight
.withOpacity(0.05),
))),
image: AdvancedNetworkImage(
journeyData['coverImage'],
useDiskCache: true,
cacheRule: CacheRule(
maxAge: Duration(hours: 9999))),
),
Padding(
padding: EdgeInsets.only(
top: SizeConfig.safeBlockVertical * 0.5,
left:
SizeConfig.safeBlockVertical * 0.5),
child: Text(
journeyData['title'],
style: Theme.of(context)
.textTheme
.bodyText2
.copyWith(
fontWeight: FontWeight.w500),
))
],
),
),
onTap: () {
addInterestData(
tags: journeyData['community']['hashtags']);
Navigator.push(
context,
MaterialPageRoute(
settings:
RouteSettings(name: 'journey_home'),
builder: (context) =>
JourneyHome(journeyId: journeyId)));
});
},
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
mainAxisSpacing: SizeConfig.safeBlockVertical * 2,
crossAxisSpacing: 8.0,
),
),
isLoading ? circularProgress(context) : Container()
]),
),
),
);
}
}

Screen Screenshot

最佳答案

There is also a pub package named states_rebuilder
https://pub.dev/packages/states_rebuilder
要么
我们的小部件应该有一个 setState()方法,该方法被调用,小部件被重绘

关于flutter - Flutter-如何在调用某个操作按钮时重新加载整个页面(再次以其初始化状态重新加载小部件)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63211917/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com