Closed iliyami closed 1 year ago
Thanks! 😊
I wouldn't expect this to refresh the page. Can you post a small reproducible example?
Thanks! 😊
I wouldn't expect this to refresh the page. Can you post a small reproducible example?
Sorry for the delay. This is an example:
import 'package:flutter/material.dart';
import 'package:vrouter/vrouter.dart';
void main() {
runApp(
VRouter(
debugShowCheckedModeBanner: false,
routes: [
VNester(
path: '/',
widgetBuilder: (child) =>
MyScaffold(child), // Child is the widget from nestedRoutes
nestedRoutes: [
VWidget.builder(
path: 'page/:id',
builder: (context, state) => HomeScreen(
index: int.parse(state.pathParameters['id']!)),
),
VWidget(path: 'settings', widget: const SettingsScreen()),
],
),
],
),
);
}
class MyScaffold extends StatelessWidget {
final Widget child;
const MyScaffold(this.child, {super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
currentIndex: context.vRouter.url.contains('settings') ? 1 : 0,
onTap: (value) =>
context.vRouter.to((value == 0) ? '/page/0' : '/settings'),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.settings), label: 'Settings'),
],
),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key, required this.index});
final int index;
String get title => (index == 0) ? 'followers' : 'following';
String get buttonText => 'Go to ${(index == 0) ? 'followers' : 'following'}';
String get to => '/page/${(index == 0) ? 1 : 0}';
@override
State<StatefulWidget> createState() => _HomeScreen();
}
class _HomeScreen extends State<HomeScreen> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
final controller = TabController(
length: 2,
vsync: this,
);
return Material(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 50),
Container(
color: Colors.black,
child: SizedBox(
height: 55,
child: TabBar(
controller: controller,
isScrollable: true,
indicatorPadding: const EdgeInsets.all(4),
labelPadding: const EdgeInsets.all(0),
tabs: List<Widget>.generate(2, (int index) {
if (index == 0) {
return SizedBox(
width: MediaQuery.of(context).size.width / 2,
child: const Tab(text: "followers"),
);
}
return SizedBox(
width: MediaQuery.of(context).size.width / 2,
child: const Tab(text: "following"),
);
}),
),
),
),
Expanded(
child: TabBarView(
controller: controller,
children: List.generate(2, (index) {
if (index == 0) {
return FollowersFollowing(
index: index,
);
} else {
return FollowersFollowing(
index: index,
);
}
}),
),
),
],
),
);
}
}
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
String get title => 'Settings';
String get buttonText => 'Go to Home';
String get to => '/page/0';
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(title),
const SizedBox(height: 50),
ElevatedButton(
onPressed: () => context.vRouter.to(to),
child: Text(buttonText),
),
],
),
),
);
}
}
class FollowersFollowing extends StatelessWidget {
const FollowersFollowing({super.key, required this.index});
final int index;
String get to => '/page/${(index == 0) ? 1 : 0}';
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 50),
Text((index == 0) ? 'Followers page' : 'Following page'),
],
),
),
);
}
}
The question is here, How can I change the url path param silently when changing the tab? And happy new year!
To change the url you have to make it part of your routes:
VNester(
path: 'page/:id',
widgetBuilder: (child) => child, // Child is the widget from nestedRoutes
nestedRoutes: [
VWidget.builder(
path: 'followers',
buildTransition: (_, __, child) => child,
builder: (context, state) => HomeScreen(
index: int.parse(
state.pathParameters['id']!,
),
selectedTab: HomeTabItem.followers,
),
),
VWidget.builder(
path: 'following',
buildTransition: (_, __, child) => child,
builder: (context, state) => HomeScreen(
index: int.parse(
state.pathParameters['id']!,
),
selectedTab: HomeTabItem.following,
),
),
],
)
To do it "silently" I guess you mean no animation so you would override buildTransition
:
VWidget.builder(
buildTransition: (_, __, child) => child,
...
)
To change the url you have to make it part of your routes:
VNester( path: 'page/:id', widgetBuilder: (child) => child, // Child is the widget from nestedRoutes nestedRoutes: [ VWidget.builder( path: 'followers', buildTransition: (_, __, child) => child, builder: (context, state) => HomeScreen( index: int.parse( state.pathParameters['id']!, ), selectedTab: HomeTabItem.followers, ), ), VWidget.builder( path: 'following', buildTransition: (_, __, child) => child, builder: (context, state) => HomeScreen( index: int.parse( state.pathParameters['id']!, ), selectedTab: HomeTabItem.following, ), ), ], )
To do it "silently" I guess you mean no animation so you would override
buildTransition
:VWidget.builder( buildTransition: (_, __, child) => child, ... )
Here is the entire code Thanks for the reply and code.
By do it silently, I mean I want to change the url and avoid starting page from the scratch (Animations, API calls, rebuilds, and ...) I just want to change the url in the current page without affecting on anything except the url! Is it possible?
Imagine you have a listview.builder and the current URL is listview/item_1 and you want to change the URL based on the listview items as you scroll them down or up -> listview/item_2 listview/item_3 etc.
VRouter does not control the state of your app differently than any other widget: If a widget (or its key) at the top changes, it will rebuild its children.
What you might be missing is that VRouter uses the resolved path as a key, so if you use
VWidget.builder(
path: '/items/:id',
builder: (context, data) => MyList(
currentItemId: int.parse(data.pathParameters['id']!),
),
)
to create a list, indeed the list will be "rebuilt" every time. What you have to do in this case is to fix the key, which you can do with the key
parameter:
VWidget.builder(
key: const ValueKey('items'),
path: '/items/:id',
builder: (context, data) => MyList(
currentItemId: int.parse(data.pathParameters['id']!),
),
)
I totally got it. Thanks for the explanation and the demo . It was very helpful🔥
Hi @lulupointu First of all, thanks for this strong package, I can't even compare it with go_router... It's a pity that the go_router went more popular than this package, so thanks for your efforts.
I have a question, I want to change the url without refreshing the page. How can I achieve that?
For example I have this in my url: post/1536 Then I want to change it to post/someID when user start scrolling the posts. If I use context.vRouter.to or toNamed with new path params, potentially it'll be start refreshing and I want to avoid this.