{"id":325959,"date":"2021-07-05T09:00:13","date_gmt":"2021-07-05T09:00:13","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=325959"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=325959","title":{"rendered":"\u0422\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440. \u0414\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0441\u043b\u043e\u0436\u043d\u043e c \u043f\u043e\u043c\u043e\u0449\u044c\u044e Flutter"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442!<\/p>\n<p>\u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 <a href=\"https:\/\/links.appmemo.ru\/habr\" rel=\"noopener noreferrer nofollow\">Memo<\/a>. <\/p>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043c\u044b \u0432\u044b\u043b\u043e\u0436\u0438\u043b\u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0432 \u0441\u0442\u043e\u0440\u044b \u0438 \u0442\u0443\u0442 \u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u0437\u044b\u0432 \u043e\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2fb\/b48\/fbc\/2fbb48fbcc819e0f23b8f6f3f3ec7123.png\" alt=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u041c\u0430\u043a\u0441\u0438\u043c!\" title=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u041c\u0430\u043a\u0441\u0438\u043c!\" width=\"780\" height=\"440\"><figcaption>\u041f\u0440\u0438\u0432\u0435\u0442, \u041c\u0430\u043a\u0441\u0438\u043c!<\/figcaption><\/figure>\n<p>\u0422\u0443\u0442 \u044f \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b \u043f\u0440\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Meduza (\u0438\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439 \u0430\u0433\u0435\u043d\u0442):<\/p>\n<p><iframe id=\"60e1fa4b9b18798fbe34cb76\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/60e1fa4b9b18798fbe34cb76\" class=\"embed_video embed__content\" allowfullscreen=\"true\"><\/iframe><\/p>\n<p>\u042f \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c Android \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u043c \u0438 \u0434\u0430\u0436\u0435 \u043d\u0435 \u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u043e. \u041e\u0442\u043a\u0440\u044b\u0432 iOS \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u044f \u0443\u0432\u0438\u0434\u0435\u043b, \u0447\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043d\u0438 \u043a \u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0430\u043a\u0446\u0438\u0438.<\/p>\n<p>\u041e \u0447\u0435\u043c \u0440\u0435\u0447\u044c? \u0412 iOS \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0430\u044f \u0444\u0438\u0447\u0430 &#8212; <a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/uiscrollview\/1619421-scrollstotop\" rel=\"noopener noreferrer nofollow\">scrolls to top<\/a>. \u0412\u043e\u0442, \u043a\u0430\u043a \u043d\u0430\u043c \u0435\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f:<\/p>\n<blockquote>\n<p>The scroll-to-top gesture is a tap on the status bar. When a user makes this gesture, the system asks the scroll view closest to the status bar to scroll to the top<\/p>\n<\/blockquote>\n<h3>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a\u043e\u0434\u0443<\/h3>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043c\u043e\u0436\u0435\u0442 \u043b\u0438 Flutter \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u043c \u0442\u0430\u043a\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438? \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0435\u043c\u043f\u043b \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u044d\u043a\u0440\u0430\u043d\u043e\u043c \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c:<\/p>\n<pre><code class=\"dart\">import 'package:example\/home_page.dart'; import 'package:flutter\/material.dart';  void main() {   runApp(const MyApp()); } class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);   @override   Widget build(BuildContext context) {     return const MaterialApp(title: 'Scroll to top', home: HomePage());   } } <\/code><\/pre>\n<pre><code class=\"dart\">import 'package:flutter\/material.dart';  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);    @override   State&lt;HomePage&gt; createState() =&gt; _HomePageState(); }  class _HomePageState extends State&lt;HomePage&gt; {   @override   Widget build(BuildContext context) {     return Scaffold(       body: _list(),       appBar: AppBar(title: const Text('Scroll to top')),     );   }    Widget _list() {     return ListView.builder(itemBuilder: _itemBuilder, itemCount: 100);   }      Widget _itemBuilder(BuildContext context, int index) {     return Container(       decoration: BoxDecoration(         border: Border.all(color: Colors.blue),       ),       padding: const EdgeInsets.all(20),       child: Text('$index', style: const TextStyle(fontSize: 20)),     );   } } <\/code><\/pre>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u0440\u043e\u0441\u043a\u0440\u043e\u043b\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 (\u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u043e \u0442\u0430\u043f\u0430, <a href=\"https:\/\/medium.com\/@ant_one\/show-touch-highlights-on-ios-simulator-37c7cc081a2a\" rel=\"noopener noreferrer nofollow\">\u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u0430\u044f<\/a> \u0437\u0430\u0434\u0430\u0447\u0430)<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/84c\/182\/ee7\/84c182ee72da459b26ec172bccda5080.gif\" width=\"600\" height=\"1265\"><figcaption><\/figcaption><\/figure>\n<p>\u041a\u0440\u0443\u0442\u043e, \u0444\u0438\u0447\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. \u041c\u043e\u0436\u0435\u043c \u0440\u0430\u0441\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f?<\/p>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043d\u0430\u043c \u0438\u043d\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 <code>ScrollController<\/code> \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043a\u0440\u043e\u043b\u043e\u0432 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c \u0441\u043f\u0438\u0441\u043a\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440:<\/p>\n<pre><code class=\"dart\">import 'package:flutter\/material.dart';  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);   @override   State&lt;HomePage&gt; createState() =&gt; _HomePageState(); } class _HomePageState extends State&lt;HomePage&gt; {   late ScrollController _scrollController;   @override   void initState() {     super.initState();     _scrollController = ScrollController();   }   @override   void dispose() {     _scrollController.dispose();     super.dispose();   }   @override   Widget build(BuildContext context) {     return Scaffold(       body: _list(),       appBar: AppBar(title: const Text('Scroll to top')),     );   }   Widget _list() {     return ListView.builder(       itemBuilder: _itemBuilder,       itemCount: 100,       controller: _scrollController,     );   } Widget _itemBuilder(BuildContext context, int index) { return Container(   decoration: BoxDecoration(     border: Border.all(color: Colors.blue),   ),   padding: const EdgeInsets.all(20),   child: Text('$index', style: const TextStyle(fontSize: 20)), );    } }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0435\u0442 \u0441\u043a\u0440\u043e\u043b\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f. \u0417\u0430 \u0441\u0447\u0435\u0442 \u0447\u0435\u0433\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a? \u042f \u043f\u043e\u0438\u0441\u043a\u0430\u043b \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c Flutter \u0438 \u043d\u0430\u0448\u0435\u043b \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/material\/scaffold.dart\" rel=\"noopener noreferrer nofollow\">Scaffold<\/a>:<\/p>\n<pre><code class=\"dart\">\/\/ iOS FEATURES - status bar tap, back gesture    \/\/ On iOS, tapping the status bar scrolls the app's primary scrollable to the   \/\/ top. We implement this by looking up the  primary scroll controller and   \/\/ scrolling it to the top when tapped.   void _handleStatusBarTap() {     final ScrollController? _primaryScrollController = PrimaryScrollController.of(context);     if (_primaryScrollController != null &amp;&amp; _primaryScrollController.hasClients) {       _primaryScrollController.animateTo(         0.0,         duration: const Duration(milliseconds: 300),         curve: Curves.linear, \/\/ TODO(ianh): Use a more appropriate curve.       );     }   }<\/code><\/pre>\n<p>\u0415\u0441\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0436\u0435\u0441\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0432\u043e\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434<code>_handleStatusBarTap<\/code> (\u043e\u0431\u043e\u0436\u0430\u044e <a href=\"https:\/\/github.com\/flutter\/flutter\/blame\/db930ba32f320cb0ca53595a2df0e4a9fe15101d\/packages\/flutter\/lib\/src\/material\/scaffold.dart#L2957\" rel=\"noopener noreferrer nofollow\">TODO<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0438\u0441\u044f\u0442 \u0432 \u0440\u0435\u043b\u0438\u0437\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043f\u043e 4 \u0433\u043e\u0434\u0430 &lt;3).<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/53c\/04e\/610\/53c04e610f9fac60f07147ab44af3f0f.png\" width=\"2912\" height=\"840\"><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0442\u0430\u043a, Flutter \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0439\u0442\u0438 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u043a \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443 <code>PrimaryScrollController<\/code> \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u0435\u0433\u043e \u0441\u043a\u0440\u043e\u043b\u0438\u0442\u044c. \u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/primary_scroll_controller.dart\" rel=\"noopener noreferrer nofollow\">PrimaryScrollController<\/a> ?<\/p>\n<pre><code class=\"dart\">\/\/\/ Associates a [ScrollController] with a subtree. \/\/\/ \/\/\/ When a [ScrollView] has [ScrollView.primary] set to true and is not given \/\/\/ an explicit [ScrollController], the [ScrollView] uses [of] to find the \/\/\/ [ScrollController] associated with its subtree. \/\/\/ \/\/\/ This mechanism can be used to provide default behavior for scroll views in a \/\/\/ subtree. For example, the [Scaffold] uses this mechanism to implement the \/\/\/ scroll-to-top gesture on iOS. \/\/\/ \/\/\/ Another default behavior handled by the PrimaryScrollController is default \/\/\/ [ScrollAction]s. If a ScrollAction is not handled by an otherwise focused \/\/\/ part of the application, the ScrollAction will be evaluated using the scroll \/\/\/ view associated with a PrimaryScrollController, for example, when executing \/\/\/ [Shortcuts] key events like page up and down. \/\/\/ \/\/\/ See also: \/\/\/   * [ScrollAction], an [Action] that scrolls the [Scrollable] that encloses \/\/\/     the current [primaryFocus] or is attached to the PrimaryScrollController. \/\/\/   * [Shortcuts], a widget that establishes a [ShortcutManager] to be used \/\/\/     by its descendants when invoking an [Action] via a keyboard key \/\/\/     combination that maps to an [Intent]. class PrimaryScrollController extends InheritedWidget {   \/\/\/ Creates a widget that associates a [ScrollController] with a subtree.   const PrimaryScrollController({     Key? key,     required ScrollController this.controller,     required Widget child,   }) : assert(controller != null),        super(key: key, child: child);<\/code><\/pre>\n<p><code>PrimaryScrollController<\/code> \u2013 \u044d\u0442\u043e \u043d\u0435 <code>ScrollController<\/code>, \u043a\u0430\u043a \u043c\u043e\u0433\u043b\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f. \u042d\u0442\u043e \u0432\u0438\u0434\u0436\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u0440\u0436\u0438\u0442 <code>ScrollController<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 primary \u0441\u043a\u0440\u043e\u043b\u043b \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>\u0412\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0442\u0440\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u0443\u0434\u0430 \u0431\u0435\u0440\u0435\u0442\u0441\u044f PrimaryScrollController?<\/p>\n<\/li>\n<li>\n<p>\u0411\u0443\u0434\u0435\u0442 \u043b\u0438 \u044d\u0442\u043e \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 <code>Scaffold<\/code>?<\/p>\n<\/li>\n<\/ol>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/h4>\n<p>\u0417\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432 \u043a\u043b\u0430\u0441\u0441 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/scroll_view.dart\" rel=\"noopener noreferrer nofollow\">ScrollView<\/a>:<\/p>\n<pre><code class=\"dart\">final ScrollController? scrollController =         primary ? PrimaryScrollController.of(context) : controller<\/code><\/pre>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0444\u043b\u0430\u0433 <code>primary<\/code>, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d <code>PrimaryScrollController<\/code> \u2013 \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u0432\u0438\u0434\u0436\u0435\u0442 \u043d\u0430\u0447\u043d\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0442\u0430\u043f\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440.<\/p>\n<p>\u0427\u0442\u043e \u0437\u0430 \u0444\u043b\u0430\u0433 <code>primary<\/code>? \u0421\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e:<\/p>\n<pre><code class=\"dart\">\/\/\/ Also when true, the scroll view is used for default [ScrollAction]s. If a \/\/\/ ScrollAction is not handled by an otherwise focused part of the application, \/\/\/ the ScrollAction will be evaluated using this scroll view, for example, \/\/\/ when executing [Shortcuts] key events like page up and down. \/\/\/ \/\/\/ On iOS, this also identifies the scroll view that will scroll to top in \/\/\/ response to a tap in the status bar. \/\/\/ {@endtemplate} \/\/\/<\/code><\/pre>\n<p>\u0424\u043b\u0430\u0433 <code>primary<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c <code>ScrollView<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0442\u0430\u043f\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440. \u041e\u043a\u0435\u0439. \u041d\u043e \u043c\u044b \u043d\u0435 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u041a\u0430\u043a\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e?<\/p>\n<pre><code class=\"dart\">\/\/\/ Defaults to true when [scrollDirection] is [Axis.vertical] and \/\/\/ [controller] is null. final bool primary;<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u044f\u0432\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>primary<\/code>, \u0442\u043e \u0444\u043b\u0430\u0433 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 <code>true<\/code>, \u0435\u0441\u043b\u0438 \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0438 <code>controller == null<\/code>. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>false<\/code>.<\/p>\n<pre><code class=\"dart\">primary = primary ?? controller == null &amp;&amp; identical(scrollDirection, Axis.vertical),<\/code><\/pre>\n<h3>\u041e\u0442\u043a\u0443\u0434\u0430 \u0431\u0435\u0440\u0435\u0442\u0441\u044f PrimaryScrollController<\/h3>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0434\u0435\u0431\u0430\u0433\u0435\u0440 \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u043c\u0435\u0442\u043e\u0434 <code>static ScrollController? of(BuildContext context)<\/code> \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/primary_scroll_controller.dart\" rel=\"noopener noreferrer nofollow\">PrimaryScrollController<\/a>. \u041e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442 <code>PrimaryScrollController<\/code> \u0438\u0437 <code>routes<\/code>(\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>_location<\/code>):<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5b6\/b92\/f29\/5b6b92f2935e7c753d911d5999de0b6b.png\" width=\"2348\" height=\"364\"><figcaption><\/figcaption><\/figure>\n<p>\u041a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0438\u0441\u043a \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>dependOnInheritedWidgetOfExactType<\/code> , \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u0432\u043e\u0442 \u044d\u0442\u043e <a href=\"https:\/\/www.youtube.com\/watch?v=Zbm3hjPjQMk&amp;ab_channel=GoogleDevelopers\" rel=\"noopener noreferrer nofollow\">\u0432\u0438\u0434\u0435\u043e<\/a>. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e: \u043c\u0435\u0442\u043e\u0434 <code>dependOnInheritedWidgetOfExactType<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0439\u0442\u0438\u0441\u044c \u0432\u0432\u0435\u0440\u0445 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432 \u0438 \u043d\u0430\u0439\u0442\u0438 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u0432\u0438\u0434\u0436\u0435\u0442 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b\u0448\u0435 \u043f\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e <code>Scaffold<\/code> \u043d\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e <code>PrimaryScrollController<\/code>, \u0442\u043e \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u0434\u0435\u043c \u043a <code>PrimaryScrollController<\/code> \u0438\u0437 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/routes.dart\" rel=\"noopener noreferrer nofollow\">routes.dart:<\/a><\/p>\n<pre><code class=\"dart\">\/\/... @override Widget build(BuildContext context) {   return AnimatedBuilder(     animation: widget.route.restorationScopeId,     builder: (BuildContext context, Widget? child) {       assert(child != null);       return RestorationScope(         restorationId: widget.route.restorationScopeId.value,         child: child!,       );     },     child: _ModalScopeStatus(       route: widget.route,       isCurrent: widget.route.isCurrent, \/\/ _routeSetState is called if this updates       canPop: widget.route.canPop, \/\/ _routeSetState is called if this updates       child: Offstage(         offstage: widget.route.offstage, \/\/ _routeSetState is called if this updates         child: PageStorage(           bucket: widget.route._storageBucket, \/\/ immutable           child: Builder(             builder: (BuildContext context) {               return Actions(                 actions: &lt;Type, Action&lt;Intent&gt;&gt;{                   DismissIntent: _DismissModalAction(context),                 },                 child: PrimaryScrollController( \/\/&lt;- \u0412\u043e\u0442 \u044d\u0442\u043e \u043c\u0435\u0441\u0442\u043e \/\/...<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u0442\u043e\u0433\u0434\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043a\u0440\u043e\u043b\u043b\u0430 \u043f\u0440\u0438 \u0442\u0430\u043f\u0435 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440? \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 <code>PrimaryScrollController<\/code> \u043d\u0430\u0434 <code>Scaffold<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441\u043a\u0440\u043e\u043b\u043b\u0430 \u043f\u0440\u0438 \u0442\u0430\u043f\u0435 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440:<\/p>\n<pre><code class=\"dart\">  @override   Widget build(BuildContext context) {     return PrimaryScrollController(       controller: _scrollController,       child: Scaffold(         body: _list(),         appBar: AppBar(title: const Text('Scroll to top')),       ),     );   } <\/code><\/pre>\n<p>\u0421\u043d\u043e\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0434\u0435\u0431\u0430\u0433\u0435\u0440. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430\u0448 <code>PrimaryScrollController<\/code>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d1\/af8\/f0b\/5d1af8f0b50b68b5246143e16842cd5c.png\" width=\"2294\" height=\"394\"><figcaption><\/figcaption><\/figure>\n<h3>\u0411\u0443\u0434\u0435\u0442 \u043b\u0438 \u044d\u0442\u043e\u0442 \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 Scaffold?<\/h3>\n<p>\u0412\u043e\u0437\u044c\u043c\u0435\u043c \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0441 \u044d\u043a\u0440\u0430\u043d\u043e\u043c \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0430\u0431\u043e\u0432:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b89\/9c2\/904\/b899c2904a0cf17ffbd321391c4e390b.png\" width=\"1284\" height=\"2778\"><figcaption><\/figcaption><\/figure>\n<pre><code class=\"dart\">import 'package:example\/content_page.dart'; import 'package:flutter\/material.dart';  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);   @override   State&lt;HomePage&gt; createState() =&gt; _HomePageState(); } class _HomePageState extends State&lt;HomePage&gt; {     int _currentIndex = 0;   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(title: const Text('Scroll to top')),       body: IndexedStack(         index: _currentIndex,         children: const [           ContentPage(backgroundColor: Colors.white),           ContentPage(backgroundColor: Colors.deepOrange),           ContentPage(backgroundColor: Colors.green),         ],       ),       bottomNavigationBar: BottomNavigationBar(         onTap: _onTabTapped,         currentIndex: _currentIndex,         items: const [           BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),           BottomNavigationBarItem(icon: Icon(Icons.mail), label: 'Messages'),           BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile')         ],       ),     );   }   void _onTabTapped(int index) {     setState(() {       _currentIndex = index;     });   } }<\/code><\/pre>\n<p>\u0412 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u0445 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>PrimaryScrollController<\/code> :<\/p>\n<pre><code class=\"dart\">...   @override   Widget build(BuildContext context) {     return PrimaryScrollController(       controller: _scrollController,       child: Scaffold(         primary: true,         body: _list(),         backgroundColor: widget.backgroundColor,       ),     );   } ...<\/code><\/pre>\n<p>\u0422\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c. \u0412\u0441\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043f\u043e\u0434 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440\u043e\u043c \u0443 \u043d\u0430\u0441 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u044b\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 <code>Scaffold<\/code>, \u0438 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0412\u0438\u0434\u0436\u0435\u0442\u044b \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u043d\u0438\u0436\u0435 \u0438 \u0443\u0436\u0435 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0442\u0430\u043f. \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c?<\/p>\n<p>\u042f \u0432\u0438\u0436\u0443 \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f:<\/p>\n<ol>\n<li>\n<p>\u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0433\u043b\u0430\u0432\u043d\u044b\u0439 <code>Scaffold<\/code> \u0432 <code>PrimaryScrollController<\/code> \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 \u043d\u0443\u0436\u043d\u044b\u0439 \u0442\u0430\u0431;<\/p>\n<\/li>\n<li>\n<p>\u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u0445 \u0442\u0430\u0431\u043e\u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043b\u0438\u0441\u0435\u043d\u0435\u0440 \u0441\u043a\u0440\u043e\u043b\u043b\u043e\u0432 \u0434\u043b\u044f <code>PrimaryScrollController<\/code> \u0438\u0437 <code>routes.dart<\/code><\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0438\u0439, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0433\u043e \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>ScrollContext<\/code> (\u044d\u0442\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e <code>ScrollPosition<\/code>), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f animateTo:<\/p>\n<pre><code class=\"dart\">class _FakeScrollPositionWithSingleContext     extends ScrollPositionWithSingleContext {   _FakeScrollPositionWithSingleContext({     required BuildContext context,     required ScrollsToTopCallback callback,   })  : _callback = callback,         super(           physics: const NeverScrollableScrollPhysics(),           context: _FakeScrollContext(context),         );    final ScrollsToTopCallback _callback;   @override   Future&lt;void&gt; animateTo(     double to, {     required Duration duration,     required Curve curve,   }) {     return _callback(       ScrollsToTopEvent(to, duration: duration, curve: curve),     );   } }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <code>PrimaryScrollController<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u0441\u0432\u043e\u0439 \u043b\u0438\u0441\u0435\u043d\u0435\u0440. \u0423 <code>ScrollController<\/code> \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>attach<\/code>:<\/p>\n<pre><code class=\"dart\">void _attach(BuildContext context) {     final primaryScrollController = PrimaryScrollController.of(context);     if (primaryScrollController == null) return;  final scrollPositionWithSingleContext =     _FakeScrollPositionWithSingleContext(   context: context,   callback: widget.onScrollsToTop, ); primaryScrollController.attach(scrollPositionWithSingleContext);  _primaryScrollController = primaryScrollController; _scrollPositionWithSingleContext = scrollPositionWithSingleContext;    }<\/code><\/pre>\n<p>\u0418 \u0437\u0430\u0432\u0435\u0440\u043d\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0432\u0438\u0434\u0436\u0435\u0442:<\/p>\n<pre><code class=\"dart\">\/\/\/ Widget for catch scrolls-to-top event class ScrollsToTop extends StatefulWidget {   \/\/\/ Creates new ScrollsToTop widget   const ScrollsToTop({     Key? key,     required this.scaffold,     required this.onScrollsToTop,   }) : super(key: key);    \/\/\/ Primary scaffold of your app   final Scaffold scaffold;   \/\/\/ Callback for handle scrolls-to-top event   final ScrollsToTopCallback onScrollsToTop;   @override   State&lt;ScrollsToTop&gt; createState() =&gt; _ScrollsToTopState(); }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u0432\u0438\u0434\u0436\u0435\u0442 \u0432 <code>ScrollsToTop<\/code> \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0442\u0430\u043f\u044b \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0433\u0434\u0435 \u043d\u0430\u043c \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e. \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/optimist-dev\/scrolls_to_top\/tree\/main\/example\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435: <code>PrimaryScrollController<\/code> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0443\u0447\u0430\u0441\u0442\u043a\u0430\u043c\u0438 \u043a\u043e\u0434\u0430, \u043d\u0435\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0442\u0430\u043f\u043e\u043c \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 page up \/ page down.<\/p>\n<p>\u0412\u0435\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u044f \u0432\u044b\u0434\u0435\u043b\u0438\u043b \u0432 \u043f\u0430\u043a\u0435\u0442 \u0438 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u0432 <a href=\"https:\/\/pub.dev\/packages\/scrolls_to_top\" rel=\"noopener noreferrer nofollow\">pub<\/a>. \u0411\u0443\u0434\u0443 \u043e\u0447\u0435\u043d\u044c \u0440\u0430\u0434 \u043f\u0443\u043b \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430\u043c.<\/p>\n<p>\u041a\u0430\u043a \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438: Memo \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043f\u043e\u0434 <a href=\"https:\/\/apps.apple.com\/ru\/app\/memo-%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9-%D0%BF%D0%BE-%D0%BC%D0%B5%D0%BC%D0%B0%D0%BC-gif\/id1546558413?ref=pikabu.ru\" rel=\"noopener noreferrer nofollow\">iOS<\/a> \u0438 <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=dev.optimist.worddaily&amp;hl=ru&amp;gl=US&amp;ref=pikabu.ru\" rel=\"noopener noreferrer nofollow\">Android<\/a><\/p>\n<p>\u0427\u0430\u043e!<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/45b\/3a2\/332\/45b3a2332ad5108e831637e43f1aa52e.png\" width=\"1024\" height=\"1024\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/566080\/\"> https:\/\/habr.com\/ru\/post\/566080\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442!<\/p>\n<p>\u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430 <a href=\"https:\/\/links.appmemo.ru\/habr\" rel=\"noopener noreferrer nofollow\">Memo<\/a>. <\/p>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043c\u044b \u0432\u044b\u043b\u043e\u0436\u0438\u043b\u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0432 \u0441\u0442\u043e\u0440\u044b \u0438 \u0442\u0443\u0442 \u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u0437\u044b\u0432 \u043e\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<figure class=\"full-width\"><figcaption>\u041f\u0440\u0438\u0432\u0435\u0442, \u041c\u0430\u043a\u0441\u0438\u043c!<\/figcaption><\/figure>\n<p>\u0422\u0443\u0442 \u044f \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b \u043f\u0440\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f Meduza (\u0438\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439 \u0430\u0433\u0435\u043d\u0442):<\/p>\n<p><iframe id=\"60e1fa4b9b18798fbe34cb76\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/60e1fa4b9b18798fbe34cb76\" class=\"embed_video embed__content\" allowfullscreen=\"true\"><\/iframe><\/p>\n<p>\u042f \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c Android \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043e\u043c \u0438 \u0434\u0430\u0436\u0435 \u043d\u0435 \u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u043e. \u041e\u0442\u043a\u0440\u044b\u0432 iOS \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u044f \u0443\u0432\u0438\u0434\u0435\u043b, \u0447\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043d\u0438 \u043a \u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0430\u043a\u0446\u0438\u0438.<\/p>\n<p>\u041e \u0447\u0435\u043c \u0440\u0435\u0447\u044c? \u0412 iOS \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0430\u044f \u0444\u0438\u0447\u0430 &#8212; <a href=\"https:\/\/developer.apple.com\/documentation\/uikit\/uiscrollview\/1619421-scrollstotop\" rel=\"noopener noreferrer nofollow\">scrolls to top<\/a>. \u0412\u043e\u0442, \u043a\u0430\u043a \u043d\u0430\u043c \u0435\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f:<\/p>\n<blockquote>\n<p>The scroll-to-top gesture is a tap on the status bar. When a user makes this gesture, the system asks the scroll view closest to the status bar to scroll to the top<\/p>\n<\/blockquote>\n<h3>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a\u043e\u0434\u0443<\/h3>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043c\u043e\u0436\u0435\u0442 \u043b\u0438 Flutter \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u043c \u0442\u0430\u043a\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438? \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0435\u043c\u043f\u043b \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u044d\u043a\u0440\u0430\u043d\u043e\u043c \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c:<\/p>\n<pre><code class=\"dart\">import 'package:example\/home_page.dart'; import 'package:flutter\/material.dart';  void main() {   runApp(const MyApp()); } class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);   @override   Widget build(BuildContext context) {     return const MaterialApp(title: 'Scroll to top', home: HomePage());   } } <\/code><\/pre>\n<pre><code class=\"dart\">import 'package:flutter\/material.dart';  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);    @override   State&lt;HomePage&gt; createState() =&gt; _HomePageState(); }  class _HomePageState extends State&lt;HomePage&gt; {   @override   Widget build(BuildContext context) {     return Scaffold(       body: _list(),       appBar: AppBar(title: const Text('Scroll to top')),     );   }    Widget _list() {     return ListView.builder(itemBuilder: _itemBuilder, itemCount: 100);   }      Widget _itemBuilder(BuildContext context, int index) {     return Container(       decoration: BoxDecoration(         border: Border.all(color: Colors.blue),       ),       padding: const EdgeInsets.all(20),       child: Text('$index', style: const TextStyle(fontSize: 20)),     );   } } <\/code><\/pre>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u0440\u043e\u0441\u043a\u0440\u043e\u043b\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 (\u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0441\u0442\u043e \u0442\u0430\u043f\u0430, <a href=\"https:\/\/medium.com\/@ant_one\/show-touch-highlights-on-ios-simulator-37c7cc081a2a\" rel=\"noopener noreferrer nofollow\">\u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u0430\u044f<\/a> \u0437\u0430\u0434\u0430\u0447\u0430)<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041a\u0440\u0443\u0442\u043e, \u0444\u0438\u0447\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. \u041c\u043e\u0436\u0435\u043c \u0440\u0430\u0441\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f?<\/p>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043d\u0430\u043c \u0438\u043d\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 <code>ScrollController<\/code> \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u043a\u0440\u043e\u043b\u043e\u0432 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c \u0441\u043f\u0438\u0441\u043a\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440:<\/p>\n<pre><code class=\"dart\">import 'package:flutter\/material.dart';  class HomePage extends StatefulWidget {   const HomePage({Key? key}) : super(key: key);   @override   State&lt;HomePage&gt; createState() =&gt; _HomePageState(); } class _HomePageState extends State&lt;HomePage&gt; {   late ScrollController _scrollController;   @override   void initState() {     super.initState();     _scrollController = ScrollController();   }   @override   void dispose() {     _scrollController.dispose();     super.dispose();   }   @override   Widget build(BuildContext context) {     return Scaffold(       body: _list(),       appBar: AppBar(title: const Text('Scroll to top')),     );   }   Widget _list() {     return ListView.builder(       itemBuilder: _itemBuilder,       itemCount: 100,       controller: _scrollController,     );   } Widget _itemBuilder(BuildContext context, int index) { return Container(   decoration: BoxDecoration(     border: Border.all(color: Colors.blue),   ),   padding: const EdgeInsets.all(20),   child: Text('$index', style: const TextStyle(fontSize: 20)), );    } }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0435\u0442 \u0441\u043a\u0440\u043e\u043b\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f. \u0417\u0430 \u0441\u0447\u0435\u0442 \u0447\u0435\u0433\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a? \u042f \u043f\u043e\u0438\u0441\u043a\u0430\u043b \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c Flutter \u0438 \u043d\u0430\u0448\u0435\u043b \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/material\/scaffold.dart\" rel=\"noopener noreferrer nofollow\">Scaffold<\/a>:<\/p>\n<pre><code class=\"dart\">\/\/ iOS FEATURES - status bar tap, back gesture    \/\/ On iOS, tapping the status bar scrolls the app's primary scrollable to the   \/\/ top. We implement this by looking up the  primary scroll controller and   \/\/ scrolling it to the top when tapped.   void _handleStatusBarTap() {     final ScrollController? _primaryScrollController = PrimaryScrollController.of(context);     if (_primaryScrollController != null &amp;&amp; _primaryScrollController.hasClients) {       _primaryScrollController.animateTo(         0.0,         duration: const Duration(milliseconds: 300),         curve: Curves.linear, \/\/ TODO(ianh): Use a more appropriate curve.       );     }   }<\/code><\/pre>\n<p>\u0415\u0441\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0436\u0435\u0441\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0432\u043e\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434<code>_handleStatusBarTap<\/code> (\u043e\u0431\u043e\u0436\u0430\u044e <a href=\"https:\/\/github.com\/flutter\/flutter\/blame\/db930ba32f320cb0ca53595a2df0e4a9fe15101d\/packages\/flutter\/lib\/src\/material\/scaffold.dart#L2957\" rel=\"noopener noreferrer nofollow\">TODO<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0438\u0441\u044f\u0442 \u0432 \u0440\u0435\u043b\u0438\u0437\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043f\u043e 4 \u0433\u043e\u0434\u0430 &lt;3).<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0442\u0430\u043a, Flutter \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0439\u0442\u0438 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u043a \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443 <code>PrimaryScrollController<\/code> \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u0435\u0433\u043e \u0441\u043a\u0440\u043e\u043b\u0438\u0442\u044c. \u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/primary_scroll_controller.dart\" rel=\"noopener noreferrer nofollow\">PrimaryScrollController<\/a> ?<\/p>\n<pre><code class=\"dart\">\/\/\/ Associates a [ScrollController] with a subtree. \/\/\/ \/\/\/ When a [ScrollView] has [ScrollView.primary] set to true and is not given \/\/\/ an explicit [ScrollController], the [ScrollView] uses [of] to find the \/\/\/ [ScrollController] associated with its subtree. \/\/\/ \/\/\/ This mechanism can be used to provide default behavior for scroll views in a \/\/\/ subtree. For example, the [Scaffold] uses this mechanism to implement the \/\/\/ scroll-to-top gesture on iOS. \/\/\/ \/\/\/ Another default behavior handled by the PrimaryScrollController is default \/\/\/ [ScrollAction]s. If a ScrollAction is not handled by an otherwise focused \/\/\/ part of the application, the ScrollAction will be evaluated using the scroll \/\/\/ view associated with a PrimaryScrollController, for example, when executing \/\/\/ [Shortcuts] key events like page up and down. \/\/\/ \/\/\/ See also: \/\/\/   * [ScrollAction], an [Action] that scrolls the [Scrollable] that encloses \/\/\/     the current [primaryFocus] or is attached to the PrimaryScrollController. \/\/\/   * [Shortcuts], a widget that establishes a [ShortcutManager] to be used \/\/\/     by its descendants when invoking an [Action] via a keyboard key \/\/\/     combination that maps to an [Intent]. class PrimaryScrollController extends InheritedWidget {   \/\/\/ Creates a widget that associates a [ScrollController] with a subtree.   const PrimaryScrollController({     Key? key,     required ScrollController this.controller,     required Widget child,   }) : assert(controller != null),        super(key: key, child: child);<\/code><\/pre>\n<p><code>PrimaryScrollController<\/code> \u2013 \u044d\u0442\u043e \u043d\u0435 <code>ScrollController<\/code>, \u043a\u0430\u043a \u043c\u043e\u0433\u043b\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f. \u042d\u0442\u043e \u0432\u0438\u0434\u0436\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u0440\u0436\u0438\u0442 <code>ScrollController<\/code>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 primary \u0441\u043a\u0440\u043e\u043b\u043b \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>\u0412\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0442\u0440\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043a\u0443\u0434\u0430 \u0431\u0435\u0440\u0435\u0442\u0441\u044f PrimaryScrollController?<\/p>\n<\/li>\n<li>\n<p>\u0411\u0443\u0434\u0435\u0442 \u043b\u0438 \u044d\u0442\u043e \u0442\u0430\u043f \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 <code>Scaffold<\/code>?<\/p>\n<\/li>\n<\/ol>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442?<\/h4>\n<p>\u0417\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432 \u043a\u043b\u0430\u0441\u0441 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/scroll_view.dart\" rel=\"noopener noreferrer nofollow\">ScrollView<\/a>:<\/p>\n<pre><code class=\"dart\">final ScrollController? scrollController =         primary ? PrimaryScrollController.of(context) : controller<\/code><\/pre>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0444\u043b\u0430\u0433 <code>primary<\/code>, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d <code>PrimaryScrollController<\/code> \u2013 \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u0432\u0438\u0434\u0436\u0435\u0442 \u043d\u0430\u0447\u043d\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0442\u0430\u043f\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440.<\/p>\n<p>\u0427\u0442\u043e \u0437\u0430 \u0444\u043b\u0430\u0433 <code>primary<\/code>? \u0421\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e:<\/p>\n<pre><code class=\"dart\">\/\/\/ Also when true, the scroll view is used for default [ScrollAction]s. If a \/\/\/ ScrollAction is not handled by an otherwise focused part of the application, \/\/\/ the ScrollAction will be evaluated using this scroll view, for example, \/\/\/ when executing [Shortcuts] key events like page up and down. \/\/\/ \/\/\/ On iOS, this also identifies the scroll view that will scroll to top in \/\/\/ response to a tap in the status bar. \/\/\/ {@endtemplate} \/\/\/<\/code><\/pre>\n<p>\u0424\u043b\u0430\u0433 <code>primary<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c <code>ScrollView<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0442\u0430\u043f\u0430 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440. \u041e\u043a\u0435\u0439. \u041d\u043e \u043c\u044b \u043d\u0435 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u041a\u0430\u043a\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e?<\/p>\n<pre><code class=\"dart\">\/\/\/ Defaults to true when [scrollDirection] is [Axis.vertical] and \/\/\/ [controller] is null. final bool primary;<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u044f\u0432\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>primary<\/code>, \u0442\u043e \u0444\u043b\u0430\u0433 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 <code>true<\/code>, \u0435\u0441\u043b\u0438 \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0438 <code>controller == null<\/code>. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>false<\/code>.<\/p>\n<pre><code class=\"dart\">primary = primary ?? controller == null &amp;&amp; identical(scrollDirection, Axis.vertical),<\/code><\/pre>\n<h3>\u041e\u0442\u043a\u0443\u0434\u0430 \u0431\u0435\u0440\u0435\u0442\u0441\u044f PrimaryScrollController<\/h3>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0434\u0435\u0431\u0430\u0433\u0435\u0440 \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u043c\u0435\u0442\u043e\u0434 <code>static ScrollController? of(BuildContext context)<\/code> \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/primary_scroll_controller.dart\" rel=\"noopener noreferrer nofollow\">PrimaryScrollController<\/a>. \u041e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442 <code>PrimaryScrollController<\/code> \u0438\u0437 <code>routes<\/code>(\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>_location<\/code>):<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0438\u0441\u043a \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>dependOnInheritedWidgetOfExactType<\/code> , \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u0432\u043e\u0442 \u044d\u0442\u043e <a href=\"https:\/\/www.youtube.com\/watch?v=Zbm3hjPjQMk&amp;ab_channel=GoogleDevelopers\" rel=\"noopener noreferrer nofollow\">\u0432\u0438\u0434\u0435\u043e<\/a>. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e: \u043c\u0435\u0442\u043e\u0434 <code>dependOnInheritedWidgetOfExactType<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0439\u0442\u0438\u0441\u044c \u0432\u0432\u0435\u0440\u0445 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432 \u0438 \u043d\u0430\u0439\u0442\u0438 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u0432\u0438\u0434\u0436\u0435\u0442 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b\u0448\u0435 \u043f\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e <code>Scaffold<\/code> \u043d\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e <code>PrimaryScrollController<\/code>, \u0442\u043e \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u0434\u0435\u043c \u043a <code>PrimaryScrollController<\/code> \u0438\u0437 <a href=\"https:\/\/github.com\/flutter\/flutter\/blob\/master\/packages\/flutter\/lib\/src\/widgets\/routes.dart\" rel=\"noopener noreferrer nofollow\">routes.dart:<\/a><\/p>\n<pre><code class=\"dart\">\/\/... @override Widget build(BuildContext context) {   return AnimatedBuilder(     animation: widget.route.restorationScopeId,     builder: (BuildContext context, Widget? child) {       assert(child != null);       return RestorationScope(         restorationId: widget.route.restorationScopeId.value,         child: child!,       );     },     child: _ModalScopeStatus(       route: widget.route,       isCurrent: widget.route.isCurrent, \/\/ _routeSetState is called if this updates       canPop: widget.route.canPop, \/\/ _routeSetState is called if this updates       child: Offstage(         offstage: widget.route.offstage, \/\/ _routeSetState is called if this updates         child: PageStorage(           bucket: widget.route._storageBucket, \/\/ immutable           child: Builder(             builder: (BuildContext context) {               return Actions(                 actions: &lt;Type, Action&lt;Intent&gt;&gt;{                   DismissIntent: _DismissModalAction(context),                 },                 child: PrimaryScrollController( \/\/&lt;- \u0412\u043e\u0442 \u044d\u0442\u043e \u043c\u0435\u0441\u0442\u043e \/\/...<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u0442\u043e\u0433\u0434\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043a\u0440\u043e\u043b\u043b\u0430 \u043f\u0440\u0438 \u0442\u0430\u043f\u0435 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440? \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 <code>PrimaryScrollController<\/code> \u043d\u0430\u0434 <code>Scaffold<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441\u043a\u0440\u043e\u043b\u043b\u0430 \u043f\u0440\u0438 \u0442\u0430\u043f\u0435 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441 \u0431\u0430\u0440:<\/p>\n<pre><code class=\"dart\">  @override   Widget build(BuildContext context) {     return PrimaryScrollController(       controller: _scrollController,       child: Scaffold(         body: _list(),         appBar: AppBar(title: const Text('Scroll to top')),       ),     );   } <\/code><\/pre>\n<p>\u0421\u043d\u043e\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0434\u0435\u0431\u0430\u0433\u0435\u0440. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430\u0448 <code>PrimaryS<\/code><\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-325959","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/325959","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=325959"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/325959\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=325959"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=325959"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=325959"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}