flutter_page_tracker
Making connections
Introduction to the
FlutterPageTracker is a plugin that listens for pages to come and go. It has the following features:
- 1. Listen on common pages
show
andleave
Event (PageRoute),- The current page is triggered when the current page is pushed
Exposure events
And the previous pageLeave the event
. - The current page is triggered when the current page is out of the stack
Leave the event
And the previous pageExposure events
.
- The current page is triggered when the current page is pushed
- 2. Listen to the dialog box
show
andleave
(PopupRoute),- The difference with PageRoute is that the opening and closing of the current dialog does not trigger the previous page
show
,leave
The event
- The difference with PageRoute is that the opening and closing of the current dialog does not trigger the previous page
- 3. Monitor PageView and TabView components
switch
The event- When a PageView or a TabView
Into the stack
, the previous page triggers the pageLeave the event
- When a PageView or a TabView
Out of the stack
, the previous page triggers the pageExposure events
- When the focus page changes, the old page triggers the page to be exposed and the new page triggers PageView
- PageView components
- TabView components
- When a PageView or a TabView
- 4. Nested use of PageView and TabView
- We can nest the two components together without limiting the level of nesting
- The PageView (or TabView) whose focus changes and its children are affected
Exposure events
andLeave the event
- 5. Slide exposure events
- If you’re interested in slide-uncovering events for lists, you can refer to the flutter_sliver_tracker plugin
https://github.com/SBDavid/flutter_sliver_tracker
Run the Demo program
- Cloning code to the local: git clone [email protected]: SBDavid/flutter_page_tracker git
- To switch the working path: CD flutter_page_tracker/example/
- Start simulator
- Run: flutter run
use
1. Install
dependencies:
flutter_page_tracker: ^ 1.2.2
Copy the code
2. Introduce the flutter_page_tracker
import 'package:flutter_page_tracker/flutter_page_tracker.dart';
Copy the code
3. Send the event of burying a common page
3.1 Adding A Route Listener
void main() => runApp(
TrackerRouteObserverProvider(
child: MyApp(),
)
);
Copy the code
3.2 Sending buried events in components
Two mixins, PageTrackerAware and TrackerPageMixin, must be used
class HomePageState extends State<MyHomePage> with PageTrackerAware.TrackerPageMixin {
@override
Widget build(BuildContext context) {
return Container();
}
@override
void didPageView() {
super.didPageView();
// Send the page expose event
}
@override
void didPageExit() {
super.didPageExit();
// Send the page away event}}Copy the code
3.3 Dialog buried points
class PopupPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SimpleDialog(
children: <Widget>[
TrackerDialogWrapper(
didPageView: () {
// Send page exposure events
},
didPageExit: () {
// Send the page away event}, child: Container(), ), ], ); }}Copy the code
3.3 TabView sends buried events
class TabViewPage extends StatefulWidget {
TabViewPage({Key key,}) : super(key: key);
@override
_State createState() => _State();
}
class _State extends State<TabViewPage> with TickerProviderStateMixin {
TabController tabController = TabController(initialIndex: 0, length: 3, vsync: this);
@override
Widget build(BuildContext context) {
return Scaffold(
// Add the TabView wrapper
body: PageViewWrapper(
// Number of Tab pages
pageAmount: 3.// Initial Tab subscript
initialPage: 0.// Listen for the Tab onChange event
changeDelegate: TabViewChangeDelegate(tabController),
child: TabBarView(
controller: tabController,
children: <Widget>[
Builder(
builder: (_) {
// Listen for PageView, PageExit events forwarded by PageViewWrapper
return PageViewListenerWrapper(
0,
onPageView: () {
// Send page exposure events
},
onPageExit: () {
// Send the page away event}, child: Container(), ); },),// The second Tab
// The third Tab],),),); }}Copy the code
PageView can also be nested with TabView, and TabView can also be nested with TabView.
class PageViewInTabViewPage extends StatefulWidget {
@override
_State createState() => _State();
}
class _State extends State<PageViewInTabViewPage> with TickerProviderStateMixin {
TabController tabController;
PageController pageController;
@override
void initState() {
super.initState();
tabController = TabController(initialIndex: 0, length: 3, vsync: this);
pageController = PageController();
}
@override
Widget build(BuildContext context) {
return Scaffold(
/ / outer TabView
body: PageViewWrapper(
pageAmount: 3.// Number of subtabs
initialPage: 0.// The first Tab to be displayed
changeDelegate: TabViewChangeDelegate(tabController),
child: TabBarView(
controller: tabController,
children: <Widget>[
Builder(
builder: (BuildContext context) {
// Forward upper-level events
return PageViewListenerWrapper(
0./ / the inner PageView
child: PageViewWrapper(
changeDelegate: PageViewChangeDelegate(pageController),
pageAmount: 3,
initialPage: pageController.initialPage,
child: PageView(
controller: pageController,
children: <Widget>[
PageViewListenerWrapper(
0,
onPageView: () {
// Page exposure event
},
onPageExit: () {
// The page leaves the event
},
child: Container()
),
// the second page in PageView
// the third page in PageView],))); },),// tab2
// tab3],))); }}Copy the code
The principle of article
1. An overview of the
Buried point tracking of pages is usually in the last link of business development, and the development time for buried point is usually not sufficient, but buried point data is of great significance for later product adjustment, so a stable and efficient buried point framework is very important.
2. The functionality we expect from a buried point framework
2.1 PageView, PageExit event
We expect when Navigator. Of (context).pushnamed (“XXX Page”) is called; First send PageExit to the previous page and then send a PageView event to the current page. When calling the Navigator. Of (context). Pop (); , first send the PageExit event of the current page, and then send the PageView event of the previous page.
The first thing that comes to mind is to use RouteObserver, but PageView and PageExit are sent in the opposite order. And A PopupRoute type route would affect the sending of buried events on the previous page, for example we pushed the page A -> popover on page A -> page B, but the PageExit event on page A was not sent in the process.
So we have to manage the routing stack ourselves to determine the types of different routes and control the order of events. The detailed implementation is described below.
2.2 TagView component to PageView component
These two components have nothing to do with the route of the Flutter, but they still belong to the page in the eyes of the product manager. And we need to send the buried event whenever a Tab is first exposed or switched.
For example, when Tab page A is first exposed, we send the PageExit event of the previous page first, and then the PageView event of TabA. When we switch from TabA to TabB, we send TabA’s PageExit event first, and then TabB’s PageView event. When we push a new route, we need to send TabB’s PageExit event.
This process requires Tab pages to interact with regular pages through an event mechanism, and if you move this mechanism directly into business code, the business code will contain a lot of irrelevant and repetitive code. Detailed abstractions are described below.
3. Solve these problems
3.1 Solve the order problem of PageView and PageExit
RouteObserver gives us a good starting point, and we can solve this problem by overriding the didPop and didPush methods and adjusting the order in which events are sent. See TrackerStackObserver for details. In the DidPOP method we fire PageExit for the previous route and then PageView for the current route.
3.2 Avoid pop-ups (e.g., Dialog)
In routeobserver. didPop(Route Route, Route previousRoute), we can find the previousRoute by previousRoute and send the PageView event of the previousRoute to it. But if the last route was a Dialog, it would cause an error, because what we really want is the route that contains the Dialog.
To solve this problem we have to maintain a routing stack ourselves so that when didPop fires we can find the actual last route. Please refer to this code, where routes is the current routing stack.
3.3 How to report buried events in TabView and connect them with other pages
This problem can be broken down into two small questions:
-
- How do I concatenate TabView pages with normal routes?
-
- How to send buried events when Tab is switched?
To solve these two problems, we need a container that manages TAB page state and hosts event forwarding. See figure below:
The TabsWrapper will listen for routing events from the Flutter and forward them to the currently exposed Tab. This solves problem 1.
TabsWrappe also contains a TabController and the index of the last open Tab. The TabsWrappe listens for onChange(index) events from the TabController and forwards the events to the corresponding Tab.