{"id":312496,"date":"2020-11-03T15:00:50","date_gmt":"2020-11-03T15:00:50","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=312496"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=312496","title":{"rendered":"\u041f\u043e\u0447\u0435\u043c\u0443 \u044f \u0443\u0448\u0451\u043b \u0441 React Native \u0438 \u043f\u0435\u0440\u0435\u0448\u0451\u043b \u0432\u043e Flutter: \u0427\u0430\u0441\u0442\u044c 2"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0414\u043c\u0438\u0442\u0440\u0438\u0439 \u0410\u043d\u0434\u0440\u0438\u044f\u043d\u043e\u0432. \u0414\u0432\u0430 \u0433\u043e\u0434\u0430 \u044f \u043f\u0438\u0441\u0430\u043b \u043d\u0430 React Native, \u0441\u0435\u0439\u0447\u0430\u0441 \u0440\u0430\u0431\u043e\u0442\u0430\u044e <a href=\"https:\/\/surf.ru\/\">\u0432 Surf<\/a> \u0432\u043e <a href=\"https:\/\/surf.ru\/flutter\/\">Flutter \u043e\u0442\u0434\u0435\u043b\u0435<\/a> \u0438 \u0443\u0436\u0435 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0443\u0442\u043e\u0440\u0430 \u043b\u0435\u0442 \u043f\u0438\u0448\u0443 \u043d\u0430 Flutter.<\/p>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/surfstudio\/blog\/511330\/\">\u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a> \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b \u043f\u0440\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0435\u0436\u0434\u0443 React Native \u0438 Flutter.<br \/>  \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0435\u0436\u0434\u0443 React Native \u0438 Flutter \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 UI \u0434\u043b\u044f Android \u0438 iOS.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/2g\/yo\/sn\/2gyosnwbfcro12wdfgqjgfrnfio.png\"><br \/>  <a name=\"habracut\"><\/a><br \/>  <b>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e:<\/b><\/p>\n<ul>\n<li>\u041d\u0435 \u0437\u043d\u0430\u0435\u0442, \u043a\u0430\u043a\u043e\u0435 \u043a\u0440\u043e\u0441\u0441-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c, \u0438 \u0445\u043e\u0447\u0435\u0442 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0434\u0445\u043e\u0434\u0430\u043c\u0438 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/li>\n<li>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442\u0441\u044f, \u0431\u0443\u0434\u0443\u0442 \u043b\u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0432 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0438 UI \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438.<\/li>\n<li>\u041f\u0438\u0448\u0435\u0442 \u043d\u0430 React Native \u0438 \u0445\u043e\u0447\u0435\u0442 \u0443\u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c UI \u043d\u0430 Flutter.<\/li>\n<li>Flutter \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c, \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u043c\u0441\u044f React Native \u0438 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 UI.  <\/li>\n<li>\u0422\u0435\u043c, \u043a\u043e\u043c\u0443 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432.<\/li>\n<\/ul>\n<p>  \u041d\u0438\u0436\u0435 \u043f\u043e\u043a\u0430\u0436\u0443 \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 UI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Android \u0438 iOS. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u0437\u0430\u0442\u0440\u043e\u043d\u0435\u043c \u0432\u0451\u0440\u0441\u0442\u043a\u0443, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u0420\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0442\u044f\u0436\u0451\u043b\u044b\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a.<\/p>\n<p>  <i>\u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043d\u0430 Flutter \u0438 React Native \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 debug-\u0440\u0435\u0436\u0438\u043c\u0435, \u0447\u0442\u043e \u043d\u0435 \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d.<\/i><\/p>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430<\/h2>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u044d\u043a\u0440\u0430\u043d \u043d\u0430 React Native \u0438 Flutter.<\/p>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b:  <\/p>\n<ul>\n<li>\u0421\u0436\u0438\u043c\u0430\u044e\u0449\u0430\u044f\u0441\u044f \u0448\u0430\u043f\u043a\u0430.<\/li>\n<li>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438 \u043a\u043d\u043e\u043f\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0448\u0430\u043f\u043a\u0435.<\/li>\n<li>\u0421\u043a\u0440\u043e\u043b\u044f\u0449\u0438\u0439\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0435\u0441\u0442.<\/li>\n<\/ul>\n<p>  \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0441\u0436\u0438\u043c\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u0448\u0430\u043f\u043a\u0438.<\/p>\n<h4>React Native<\/h4>\n<p>  \u0418\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442, \u043d\u043e \u043d\u0430 \u0432\u044b\u0431\u043e\u0440 \u0435\u0441\u0442\u044c 3 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430:<\/p>\n<ol>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/react-native-animated-header\">\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/a>. \u041c\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b, \u0442\u0435\u043c \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043a\u0441\u0442, \u043c\u0430\u043b\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0437\u0430 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/react-native-collapsing-toolbar\">\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Android<\/a>. \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0434\u043b\u044f iOS \u043d\u0435\u0442: \u044d\u0442\u043e \u043d\u0435 \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435.  <\/li>\n<li><a href=\"https:\/\/medium.com\/@habibridho\/implementing-collapsing-toolbar-using-react-native-4a84e1718f11\">\u041a\u043e\u0434, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0432\u0440\u0443\u0447\u043d\u0443\u044e<\/a>.<\/li>\n<\/ol>\n<p>  \u0412\u044b\u0431\u0435\u0440\u0435\u043c \u0442\u0440\u0435\u0442\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<pre><code class=\"javascript\">const HEADER_EXPANDED_HEIGHT = 200 const HEADER_COLLAPSED_HEIGHT = 60 const { width: SCREEN_WIDTH } = Dimensions.get('screen')     export default function CitiesScreen() {      const screenNames = [        '\u0413\u043b\u0430\u0432\u043d\u0430\u044f',        '\u0413\u0430\u043b\u0435\u0440\u0435\u044f',    ];      const [scrollY, setScrollY] = useState(new Animated.Value(0))      let headerHeight = scrollY.interpolate({        inputRange: [0, HEADER_EXPANDED_HEIGHT - HEADER_COLLAPSED_HEIGHT],        outputRange: [HEADER_EXPANDED_HEIGHT, HEADER_COLLAPSED_HEIGHT],        extrapolate: 'clamp'    });      let heroTitleOpacity = scrollY.interpolate({        inputRange: [0, HEADER_EXPANDED_HEIGHT - HEADER_COLLAPSED_HEIGHT],        outputRange: [1, 0],        extrapolate: 'clamp'    });        return (        &lt;View style={styles.container}&gt;            &lt;SafeAreaView&gt;                &lt;View&gt;                    &lt;View style={styles.scrollWrapper}&gt;                        &lt;ScrollView                            contentContainerStyle={{                                paddingTop: HEADER_EXPANDED_HEIGHT,                                backgroundColor: 'rgba(0,0,0,.1)'                            }}                            onScroll={({                                nativeEvent: {                                    contentOffset: { x, y },                                }                            }) =&gt; {                                scrollY.setValue(y);                            }}                            scrollEventThrottle={16}                        &gt;                              &lt;View style={{ width: '100%', height: 5000 }}&gt;                              &lt;\/View&gt;                          &lt;\/ScrollView&gt;                    &lt;\/View&gt;                    &lt;Animated.View style={[                        styles.header,                        { height: headerHeight }                    ]} &gt;                        &lt;Text style={[styles.titleCollapsed]}&gt;                            Title                        &lt;\/Text&gt;                        &lt;Animated.View                            style={[styles.expandedView, { opacity: heroTitleOpacity }]}                         &gt;                            {screenNames.map((name) =&gt; (                                &lt;View                                    key='name'                                    style={{ marginHorizontal: 5 }}                                &gt;                                    &lt;Button                                        style={{                                            borderRadius: 8,                                            paddingVertical: 5,                                            paddingHorizontal: 20,                                          }}                                        onPress={() =&gt; { }}                                        title={name}                                        color=&quot;white&quot;                                    \/&gt;                                &lt;\/View&gt;                            ))}                        &lt;\/Animated.View&gt;                    &lt;\/Animated.View&gt;                  &lt;\/View&gt;            &lt;\/SafeAreaView&gt;        &lt;\/View&gt;    );     }   const styles = StyleSheet.create({    container: {        backgroundColor: 'black'    },    scrollWrapper: {        backgroundColor: 'white'    },    scrollContainer: {        padding: 16    },    header: {        width: SCREEN_WIDTH,        position: 'absolute',        top: 0,        left: 0,        backgroundColor: 'rgba(0,0,0,1)'    },    titleCollapsed: {        textAlign: 'center',        marginTop: 28,        color: 'white'    },    expandedView: {        position: 'absolute',        bottom: 16,        left: 16,        flexDirection: 'row'    } }) <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/b6\/nu\/lx\/b6nulxnydhd79fvvlxnkllsc3m8.gif\"><\/p>\n<h4>\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u043c \u0442\u043e\u0442 \u0436\u0435 UI \u043d\u0430 Flutter<\/h4>\n<p>  <\/p>\n<pre><code class=\"dart\">class CitiesScreen extends StatefulWidget {  @override  _CitiesScreenState createState() =&gt; _CitiesScreenState(); }  class _CitiesScreenState extends State&lt;CitiesScreen&gt; {  final List&lt;String&gt; screenNames = [    '\u0413\u043b\u0430\u0432\u043d\u0430\u044f',    '\u0413\u0430\u043b\u0435\u0440\u0435\u044f',  ];   @override  Widget build(BuildContext context) {    return NestedScrollView(      headerSliverBuilder: (context, _) {        return [          SliverAppBar(            backgroundColor: Colors.black.withOpacity(.9),            title: Text('Title'),            pinned: true,            centerTitle: true,            expandedHeight: 200,            flexibleSpace: FlexibleSpaceBar(              collapseMode: CollapseMode.pin,              background: Align(                alignment: Alignment.bottomLeft,                child: Container(                  height: 50,                  padding: const EdgeInsets.only(bottom: 10),                  child: Row(                    mainAxisSize: MainAxisSize.min,                    mainAxisAlignment: MainAxisAlignment.start,                    children: [                      for (String name in screenNames)                        Padding(                          padding: const EdgeInsets.symmetric(horizontal: 5),                          child: RaisedButton(                            onPressed: () {},                            color: Colors.white,                            shape: RoundedRectangleBorder(                              borderRadius: BorderRadius.circular(8),                            ),                            child: Padding(                              padding: const EdgeInsets.symmetric(                                vertical: 5,                                horizontal: 20,                              ),                              child: Center(                                child: Text(name),                              ),                            ),                          ),                        ),                    ],                  ),                ),              ),            ),          ),        ];      },      body: Container(        height: 5000,        color: Colors.black.withOpacity(.1),      ),    );  } } <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/b5\/s2\/8y\/b5s28ya04bxx80dnjhcrplbdl6o.gif\"><\/p>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0441\u0445\u043e\u0436\u0435\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435, \u043d\u043e \u0432 React Native \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u043a\u043d\u043e\u043f\u043a\u0430\u043c\u0438:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/1g\/kn\/h8\/1gknh87ke9e_ojjv0smxjzvtebi.png\"><\/p>\n<p>  \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0432 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u043c\u0443. \u041d\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0432 React Native \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u0443\u0441\u043b\u043e\u0436\u043d\u0451\u043d\u043d\u0443\u044e \u0448\u0430\u043f\u043a\u0443. \u041d\u0430 Flutter \u044f \u043e\u0431\u043e\u0448\u0451\u043b\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e SDK.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b AppBar \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u043b\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c, \u0442\u043e:  <\/p>\n<ul>\n<li>\u0412 React Native \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u0434.<\/li>\n<li>\u0412\u043e Flutter \u2014 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c pinned false.<\/li>\n<\/ul>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ng\/rx\/73\/ngrx73zfjxgoehg_b8hpifgxwq8.gif\"><\/p>\n<p>  \u0414\u043b\u044f \u0440\u0435\u0437\u043a\u043e\u0433\u043e \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f:  <\/p>\n<ul>\n<li>\u0412 RN \u2014 \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u043a\u0440\u043e\u043b\u043b\u0430 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/li>\n<li>\u0412\u043e Flutter \u2014 snap true.<\/li>\n<\/ul>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/om\/my\/4g\/ommy4g9_iewevkuj9rjmkbg__am.gif\"><\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0448\u0430\u043f\u043a\u0430 \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0430\u0441\u044c \u0447\u0435\u0440\u0435\u0437 opacity, \u0430 \u0441\u044a\u0435\u0437\u0436\u0430\u043b\u0430:  <\/p>\n<ul>\n<li>RN \u2014 \u0441\u043d\u043e\u0432\u0430 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/li>\n<li>Flutter \u2014 \u0432\u043c\u0435\u0441\u0442\u043e background \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c title.<\/li>\n<\/ul>\n<p>  <\/p>\n<div class=\"oembed\"><iframe id=\"5f9acaa4cb79a1e12d6663f2\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9acaa4cb79a1e12d6663f2\"><\/iframe><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442.<br \/>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c cities.json \u0441 \u0433\u043e\u0440\u043e\u0434\u0430\u043c\u0438 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"json\">[  \t{  \t \t&quot;id&quot;: 1,  \t \t&quot;name&quot;: String,  \t \t&quot;image&quot;: String,         }, ] <\/code><\/pre>\n<p>  <\/p>\n<h4>React Native<\/h4>\n<p>  \u0417\u0430\u043c\u0435\u043d\u0438\u043c ScrollView \u043d\u0430 FlatList \u0438 \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0433\u043e\u0440\u043e\u0434\u043e\u0432.<\/p>\n<pre><code class=\"javascript\">&lt;FlatList     contentContainerStyle={{         paddingTop: HEADER_EXPANDED_HEIGHT,         backgroundColor: 'white',     }}     onScroll={({         nativeEvent: {             contentOffset: { x, y },         }     }) =&gt; {         scrollY.setValue(y);     }}     scrollEventThrottle={16}     data={cities}     renderItem={({ item }) =&gt; {         return (             &lt;View style={{                 padding: 10,             }}&gt;                 &lt;Image                     style={{                         resizeMode: 'contain',                         flex: 1,                         aspectRatio: 1,                         borderRadius: 4,                         width: isGrid ? '69%' : 'auto'                     }}                     source={{                         uri: item.image,                     }}                 \/&gt;                 &lt;Text                     style={[                         {                             marginTop: 5,                             marginBottom: 10,                             fontSize: 24,                         }                     ]}                  &gt;                     {item.name}                 &lt;\/Text&gt;             &lt;\/View&gt;         );     }}     keyExtractor={item =&gt; item.id} &gt;   &lt;\/FlatList&gt; <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c Switch, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u0432\u044b\u0432\u043e\u0434 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0438\u043b\u0438 \u0433\u0440\u0438\u0434\u043e\u043c:<\/p>\n<pre><code class=\"javascript\">const [isGrid, setGrid] = useState(false);  &lt;Switch     value={isGrid}     onValueChange={() =&gt; setGrid(isGrid =&gt; !isGrid)}     trackColor={{ false: &quot;grey&quot;, true: &quot;white&quot; }}     thumbColor={isGrid ? &quot;white&quot; : &quot;#f4f3f4&quot;} \/&gt; <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u044b\u0432\u043e\u0434 \u0433\u0440\u0438\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">&lt;FlatList     numColumns={isGrid ? 2 : 1} <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;Text     style={[         {             marginTop: 5,             marginBottom: 10,             fontSize: 24,                                                                },         isGrid ? {             position: 'absolute',             top: 5,             left: 10         } : null     ]} &gt;     {item.name} &lt;\/Text&gt;  <\/code><\/pre>\n<p>  \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/98\/mp\/nv\/98mpnv5g3fdmhrxgjqjbndhvsz0.png\"><\/p>\n<p>  \u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, FlatList \u043d\u0430 \u043b\u0435\u0442\u0443 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043e\u043d\u043e\u043a.<\/p>\n<p>  \u0423\u043a\u0430\u0436\u0435\u043c \u043a\u043b\u044e\u0447, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u044d\u0442\u043e \u0441\u0442\u0430\u043b\u0438 \u0440\u0430\u0437\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/p>\n<pre><code class=\"javascript\">&lt;FlatList     key = {isGrid ? 'Grid' : 'List'}     numColumns={isGrid ? 2 : 1} <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/16\/2y\/eu\/162yeu6lg7iwmrfz0_8rmtczlq0.png\"><\/p>\n<p>  \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0435\u0441\u0442\u043e \u0440\u0430\u0432\u043d\u043e\u043c\u0435\u0440\u043d\u043e \u043d\u0435 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u043e\u0441\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e\u043f\u0438\u0448\u0435\u043c \u0432\u0451\u0440\u0441\u0442\u043a\u0443:<\/p>\n<pre><code class=\"javascript\">&lt;View style={{     padding: 10, }}&gt;     &lt;Image         style={{             resizeMode: 'contain',             flex: 1,             aspectRatio: 1,             borderRadius: 4,             width: isGrid ? '69%' : 'auto'         }}         source={{             uri: item.image,         }}     \/&gt;     &lt;Text         tyle={[             {                 marginTop: 5,                 marginBottom: 10,                 fontSize: 24,                                                                    },             isGrid ? {                 position: 'absolute',                 top: 5,                 left: 10             } : null         ]}     &gt;         {item.name}     &lt;\/Text&gt; &lt;\/View&gt; <\/code><\/pre>\n<p>  \u041f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043d\u0430 % \u0445\u043e\u0442\u044c \u0438 \u0441\u043f\u043e\u0440\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043d\u043e \u0440\u0430\u0431\u043e\u0447\u0435\u0435. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0432\u0451\u0440\u0441\u0442\u043a\u0443 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043b\u043e\u0430\u0434\u0435\u0440:<\/p>\n<pre><code class=\"javascript\">const [isLoading, setLoading] = useState(true);      useEffect(() =&gt; {        setTimeout(() =&gt; setLoading(false), 1000);    }, []); <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">isLoading ?     &lt;View style={{         width: '100%',         height: '100%',         justifyContent: 'center',         alignItems: 'center'     }}&gt; <\/code><\/pre>\n<p>  <a href=\"https:\/\/learn-reactjs.ru\/core\/hooks\/effect-hook\">useEffect<\/a> \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u044d\u0442\u043e\u0442 <a href=\"https:\/\/www.robinwieruch.de\/react-hooks\">\u0445\u0443\u043a<\/a>, \u0432\u044b \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442\u0435 React, \u0447\u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438. \u0412\u0442\u043e\u0440\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043c\u0430\u0441\u0441\u0438\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0438 \u0442\u043e\u0433\u0434\u0430 \u044d\u0444\u0444\u0435\u043a\u0442 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u044d\u0442\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u044d\u0444\u0444\u0435\u043a\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437.<\/p>\n<p>  \u0412 \u043d\u0451\u043c \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 API.<\/p>\n<p>  \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043a\u043e\u0434 \u043d\u0430 Android:<\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae15905d782142ffea47b\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15905d782142ffea47b\"><\/iframe><\/div>\n<p>  iOS<\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae159cb79a1e12d6663f4\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae159cb79a1e12d6663f4\"><\/iframe><\/div>\n<p>  <\/p>\n<h4>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043d\u0430 Flutter<\/h4>\n<p>  Switch:<\/p>\n<pre><code class=\"dart\">SliverAppBar(  backgroundColor: Colors.black.withOpacity(.9),  title: Row(    mainAxisAlignment: MainAxisAlignment.spaceBetween,    children: [      const SizedBox.shrink(),      Text('Title'),      Switch(        value: _isGrid,        onChanged: (bool value) {          setState(() {            _isGrid = value;          });        },      ),    ],  ), <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"dart\">body: FutureBuilder(  future: _getCities(),  builder: _buildList, ), <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"dart\">Widget _buildList(context, snapshot) {    if (snapshot.data == null) {      return Center(        child: CircularProgressIndicator(),      );    }    final cities = snapshot.data;    if (_isGrid) {      return GridView.builder(        gridDelegate:            SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),        itemBuilder: (context, int index) {          return Padding(            padding: const EdgeInsets.all(10),            child: Stack(              children: [                ClipRRect(                  borderRadius: BorderRadius.circular(4.0),                  child: Image.network(                    cities[index].image,                    width: double.infinity,                    fit: BoxFit.fill,                  ),                ),                Padding(                  padding: const EdgeInsets.only(top: 5, bottom: 10),                  child: Text(                    cities[index].name,                    style: TextStyle(fontSize: 24),                  ),                )              ],            ),          );        },      );    }    return ListView.builder(      itemCount: cities.length,      itemBuilder: (context, int index) {        return Padding(          padding: const EdgeInsets.all(10),          child: Column(            mainAxisSize: MainAxisSize.min,            crossAxisAlignment: CrossAxisAlignment.start,            children: [              ClipRRect(                borderRadius: BorderRadius.circular(4.0),                child: Image.network(                  cities[index].image,                  width: double.infinity,                  fit: BoxFit.fill,                ),              ),              Padding(                padding: const EdgeInsets.only(top: 5, bottom: 10),                child: Text(                  cities[index].name,                  style: TextStyle(fontSize: 24),                ),              )            ],          ),        );      },    );  }   Future&lt;List&lt;City&gt;&gt; _getCities() async {    String json =        await DefaultAssetBundle.of(context).loadString('res\/cities.json');     List&lt;dynamic&gt; data = jsonDecode(json);    List&lt;City&gt; result = [];    data.forEach((city) {      result.add(City(        id: city['id'],        name: city['name'],        image: city['image'],        description: city['description'],        places: city['places'],      ));    });    return result;  } }  class City {  final int id;  final String name;  final String image;  final String description;  final List&lt;dynamic&gt; places;   City({    this.id,    this.name,    this.image,    this.description,    this.places,  }); } <\/code><\/pre>\n<p>  \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c Flutter:<\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae15a2cbf1a1445b352ee\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15a2cbf1a1445b352ee\"><\/iframe><\/div>\n<p>  iOS<\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae15a102304e11bb8d5d0\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15a102304e11bb8d5d0\"><\/iframe><\/div>\n<p>  <\/p>\n<h3>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u044d\u043a\u0440\u0430\u043d\u0430<\/h3>\n<p>  <b>React Native<\/b>  <\/p>\n<ol>\n<li>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0435, \u043d\u043e \u043d\u0435\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445, \u0447\u0442\u043e \u043f\u0440\u0438 \u0435\u0434\u0438\u043d\u043e\u043c \u0434\u0438\u0437\u0430\u0439\u043d\u0435 \u0434\u043b\u044f \u043e\u0431\u0435\u0438\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0448\u0430\u0442\u044c.<\/li>\n<li>\u0418\u0437-\u0437\u0430 OEM \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432 \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0444\u0438\u0437\u0438\u043a\u0443 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u044d\u0442\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435, \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u2014 \u0443 \u043d\u0430\u0441 \u043c\u0435\u043d\u044c\u0448\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439, \u0438 \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0444\u0438\u0437\u0438\u043a\u0443 \u043f\u043e\u0434 \u0437\u0430\u0434\u0430\u0447\u0443.<\/li>\n<li>\u0427\u0442\u043e\u0431\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0432 Grid-\u0441\u0442\u0438\u043b\u0435, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0440\u0430\u0431\u043e\u0442\u044b.<\/li>\n<li>\u0414\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0433\u043e UI \u043d\u0443\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0441 \u043d\u0443\u043b\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443.<\/li>\n<li>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/li>\n<li>\u0422\u0430\u043a \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 \u043d\u043e\u0432\u044b\u0439 FlatList \u043d\u0430 \u043c\u0435\u0441\u0442\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e, \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430\u043c\u0438 \u0433\u043e\u0440\u043e\u0434\u043e\u0432 \u0432 FlatList \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0441 \u043d\u0443\u043b\u044f.<\/li>\n<\/ol>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u043a\u0430 \u043f\u0438\u0441\u0430\u043b \u0448\u0430\u043f\u043a\u0443, \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u0435\u0451 \u043d\u0430 iOS. \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u043d\u0430 Android \u2014 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0430\u0434\u0430\u0435\u0442, \u0430 \u0432 \u043b\u043e\u0433\u0430\u0445 \u043f\u0443\u0441\u0442\u043e.<\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae15ad4323713fd41587a\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15ad4323713fd41587a\"><\/iframe><\/div>\n<p>  \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0447\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430 \u2014 \u0430 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435\u0442. \u0411\u044b\u0432\u0430\u043b\u043e, \u0443 \u043c\u0435\u043d\u044f \u0432\u0441\u0451 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u043e\u0441\u044c \u00ab\u0441\u0430\u043c\u043e\u00bb, \u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u043d\u0435\u044f\u0441\u043d\u0430. \u0422\u0430\u043a\u0438\u0435 \u043d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0441\u0442\u0438 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0441\u0440\u043e\u043a\u0438.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0438 \u0440\u0435\u0448\u0438\u0442\u044c \u0435\u0451. \u041d\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u2014 \u0447\u0442\u043e \u044f \u0438 \u0441\u0434\u0435\u043b\u0430\u043b. \u042d\u0442\u043e \u0442\u043e\u0436\u0435 \u043e\u0442\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u044f, \u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b.<\/p>\n<p>  <b>Flutter<\/b>  <\/p>\n<ol>\n<li>\u0415\u0441\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u044b, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0439 UI.<\/li>\n<li>\u042d\u043a\u0440\u0430\u043d \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0438\u043b\u0430\u043c\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0434\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443.<\/li>\n<li>\u041f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043a\u0435\u0439\u0441\u043e\u0432.<\/li>\n<li>\u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, Flutter \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u043d\u0430 Android \u0438 iOS \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u044b.<\/li>\n<\/ol>\n<p>  \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 \u0432\u043e Flutter \u043d\u0435 \u043e\u0442\u0434\u0430\u0451\u0442\u0441\u044f \u043d\u0430 \u043e\u0442\u043a\u0443\u043f \u0441\u0438\u0441\u0442\u0435\u043c\u0435, \u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430. \u0422\u0430\u043a, \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u0438\u0437 Material-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u041e\u043d\u0438 \u043d\u0435 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0434\u043b\u044f iOS, \u043d\u043e \u0432\u043e Flutter \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435: \u044d\u0442\u043e \u043d\u0435 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0440\u0443\u043a\u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u043e\u0433\u043e UI. <\/p>\n<p>  \u0423\u0434\u043e\u0431\u043d\u043e \u0438 \u0442\u043e, \u0447\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0430\u043d\u0430\u043b\u043e\u0433\u0430 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0438\u0434\u0436\u0435\u0442 TextField \u0438\u0437 Material, \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043e\u0431\u0435\u0438\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445.<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 BottomSheet \u0438\u043b\u0438 \u043d\u0438\u0436\u043d\u044e\u044e \u043f\u0430\u043d\u0435\u043b\u044c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043d\u0430 \u043e\u0431\u0435\u0438\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445, \u0432\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u044d\u0442\u043e, \u043d\u0435 \u0442\u0440\u0430\u0442\u044f \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>  \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438 \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0442\u0438\u0432, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0435 \u0435\u043c\u0443 \u043d\u0435 Container \u0441 <br \/>  \u0442\u0435\u043d\u044c\u044e, \u0430 Material Card \u0441 elevation \u2014 \u0435\u0441\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0438\u0437\u0430\u0439\u043d\u0443.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0432\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u0434\u043d\u044b\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c.<br \/>  \u0412\u044b \u0441\u0430\u043c\u0438 \u0440\u0435\u0448\u0430\u0435\u0442\u0435, \u0430 Flutter \u0434\u0430\u0451\u0442 \u0432\u0430\u043c \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c. \u042d\u0442\u043e \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u0438 \u0437\u0430\u0442\u0440\u0430\u0442\u044b.<\/p>\n<h2>\u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f UI<\/h2>\n<p>  Flutter \u043d\u0435 \u0441\u0432\u044f\u0437\u0430\u043d \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f\u043c\u0438 OEM \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432: \u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u0432\u0435\u0440\u0441\u0442\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435, \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434\u0436\u0435\u0442 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0435\u0433\u043e.<\/p>\n<p>  \u041d\u0430 React Native \u0442\u043e\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u044b, \u043d\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0438\u0445 \u0441 \u043d\u0443\u043b\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f View. \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u0432\u044f\u0437\u0430\u043d\u044b \u043d\u0430 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432.<\/p>\n<p>  \u0412\u043e\u0437\u044c\u043c\u0451\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Alert \u0434\u0438\u0430\u043b\u043e\u0433.<\/p>\n<h4>React Native<\/h4>\n<p>  <\/p>\n<pre><code class=\"javascript\">Alert.alert(     &quot;Alert Title&quot;,     &quot;My Alert Msg&quot;,     [         {             text: &quot;Cancel&quot;,             onPress: () =&gt; console.log(&quot;Cancel Pressed&quot;),             style: &quot;cancel&quot;         },         { text: &quot;OK&quot;, onPress: () =&gt; console.log(&quot;OK Pressed&quot;) }     ],     { cancelable: false } ); <\/code><\/pre>\n<p>  \u0412 \u0438\u0442\u043e\u0433\u0435 \u0432\u0441\u0451, \u0447\u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c, \u2014 \u044d\u0442\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438. \u042d\u0442\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f OEM \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, React Native API.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/pg\/nc\/qi\/pgncqiqdym09qruvx2yztlr_wqc.png\"><\/p>\n<h4>Flutter<\/h4>\n<p>  <\/p>\n<pre><code class=\"dart\">showDialog(  context: context,  builder: (context) {    return AlertDialog(      title: Text('Title Dialog'),      actions: [        FlatButton(          onPressed: () {},          child: Text('Ok'),        ),      ],    );  }, ); <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ds\/yn\/dp\/dsyndp5joi88vay3s7josjqrunk.png\"><\/p>\n<p>  \u041a\u0430\u043a \u0438 \u043e\u0436\u0438\u0434\u0430\u043b\u043e\u0441\u044c, \u0432 React Native \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0441\u0430\u043c\u0430 \u0440\u0435\u0448\u0438\u043b\u0430, \u043a\u0430\u043a \u0435\u0439 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0434\u0438\u0430\u043b\u043e\u0433. \u0412\u043e Flutter \u0436\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0440\u043e\u0432\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0432\u043e\u0439 \u0432\u0438\u0434\u0436\u0435\u0442, \u0431\u0430\u0437\u0438\u0440\u0443\u044f\u0441\u044c \u043d\u0430 AlertDialog:<\/p>\n<pre><code class=\"dart\">showDialog(  context: context,  builder: (context) {    return AlertDialog(      backgroundColor: Colors.white.withOpacity(.9),      shape: BeveledRectangleBorder(        borderRadius: BorderRadius.all(          Radius.circular(20),        ),      ),      title: Text(        '\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0437\u0430 \u0442\u043e \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435\u0441\u044c \u043d\u0430\u0448\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c',        textAlign: TextAlign.center,      ),      content: SizedBox(        height: 150,        child: Icon(          Icons.tag_faces,          size: 100,          color: Colors.orange,        ),      ),      actions: [        FlatButton(          onPressed: () {},          child: Text('\u0417\u0430\u043a\u0440\u044b\u0442\u044c'),        ),      ],    );  }, ); <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/dn\/--\/oy\/dn--oyeldhqc2ed5qzai9la4trw.png\"><\/p>\n<p>  \u041c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0432\u0438\u0434\u0436\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e. \u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0432\u0437\u044f\u043b\u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 Alert:  <\/p>\n<ul>\n<li>\u041c\u043e\u0434\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u043e\u0443\u0442.<\/li>\n<li>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430.<\/li>\n<li>\u0420\u044f\u0434 \u043a\u043d\u043e\u043f\u043e\u043a \u0441\u043d\u0438\u0437\u0443.<\/li>\n<\/ul>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0432\u0430\u043c \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043a\u043e\u0449\u0443\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u0430\u0432\u0438\u0442\u044c \u00ab\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439\u00bb Alert, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u043e\u0443\u0442 \u0434\u0438\u0430\u043b\u043e\u0433\u0430 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0432\u043e\u0439 \u0432\u0438\u0434\u0436\u0435\u0442:<\/p>\n<pre><code class=\"dart\">showDialog(  context: context,  builder: (context) {    return Material(      type: MaterialType.transparency,      child: Center(        child: Container(          padding: const EdgeInsets.all(10),          decoration: BoxDecoration(            color: Colors.white,            shape: BoxShape.circle,          ),          child: Column(            mainAxisSize: MainAxisSize.min,            children: [              FlatButton(                child: Text('ok'),                onPressed: () {},              ),            ],          ),        ),      ),    );  }, ); <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/bl\/ok\/tc\/bloktciedct7kmm9i6kbudgpuue.png\"><\/p>\n<blockquote><p>\u0415\u0441\u043b\u0438 React Native \u0433\u043e\u0432\u043e\u0440\u0438\u0442: \u00ab\u0412\u043e\u0442 \u0442\u0435\u0431\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u2014 \u0442\u044b \u043c\u043e\u0436\u0435\u0448\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0442\u0430\u043a\u0438\u0445-\u0442\u043e \u043a\u0435\u0439\u0441\u0430\u0445\u00bb, \u0442\u043e Flutter \u0433\u043e\u0432\u043e\u0440\u0438\u0442: \u00ab\u0412\u043e\u0442 \u0442\u0435\u0431\u0435 \u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u044b, \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u0434 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435, \u043d\u043e \u043c\u043e\u0436\u0435\u0448\u044c \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0445\u043e\u0447\u0435\u0448\u044c\u00bb.<\/p><\/blockquote>\n<p>  \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u00ab\u043e\u0434\u0438\u043d \u043a\u043e\u0434 \u043d\u0430 \u043e\u0431\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b\u00bb \u043f\u0440\u0430\u0432\u0434\u0438\u0432\u043e \u0434\u043b\u044f \u043e\u0431\u0435\u0438\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439. \u041d\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u2014 \u0435\u0449\u0451 \u043d\u0435 \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u041d\u0443\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u0434\u0438\u043d UI \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445. React Native \u043d\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435 \u0438 \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0443\u0441\u0438\u043b\u0438\u044f\u043c\u0438 \u0438\u0437-\u0437\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f OEM \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432.<\/p>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e React Native \u2014 \u044d\u0442\u043e \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u044b\u0439 UI.<\/p>\n<h2>\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f<\/h2>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0432 \u043d\u0430\u0448\u0438 \u044d\u043a\u0440\u0430\u043d\u044b. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e API \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438.<\/p>\n<p>  \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0433\u0440\u0443\u0437\u0438\u043c \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c, \u0438 \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e.<\/p>\n<h4>React Native<\/h4>\n<p>  <\/p>\n<pre><code class=\"javascript\">let windowWidth = Dimensions.get('screen').width;   function runAnim(anim, toValue, reverseValue) {     Animated.timing(         anim,        {             toValue,             duration: 1000,        }     ).start(         () =&gt; runAnim(anim, reverseValue, toValue)    ) }   const AnimatedLoader: () =&gt; ReactNode = () =&gt; {       let loaderWidth = 100;     let maxLeft = windowWidth - loaderWidth;       const leftAnim = useRef(new Animated.Value(0)).current     const fadeAnim = leftAnim.interpolate({         inputRange: [0, maxLeft],         outputRange: [.8, 1]     });       useEffect(() =&gt; {         runAnim(leftAnim, maxLeft, 0);     }, [])       return (         &lt;Animated.View style={{             width: loaderWidth,             height: 5,             backgroundColor: 'white',             position: 'absolute',             left: leftAnim,             opacity: fadeAnim,             top: 70,         }} \/&gt;     )   } <\/code><\/pre>\n<p>  \u041f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u043d\u0430\u0434 View \u0441\u043e \u0441\u0442\u0438\u043b\u0435\u043c expandedView.<\/p>\n<pre><code class=\"javascript\">&lt;AnimatedLoader\/&gt;     &lt;Animated.View style={[styles.expandedView, { opacity: heroTitleOpacity }]}&gt; <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/4n\/oh\/qm\/4nohqmaws-6afbmaip5dqbef82w.gif\"><\/p>\n<p>  \u0422\u0430\u043a\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0432 React Native. \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043e\u0434\u043d\u043e \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Interpolate. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u043b\u0430\u0433 <a href=\"https:\/\/reactnative.dev\/blog\/2017\/02\/14\/using-native-driver-for-animated\">useNativeDriver<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0432 \u043e\u0431\u0445\u043e\u0434 \u043c\u043e\u0441\u0442\u0430 \u0438 \u043f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0435\u0451 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u2014 \u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432.<\/p>\n<p>  \u041f\u044b\u0442\u0430\u044e\u0441\u044c \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0444\u043b\u0430\u0433 useNativeDriver \u0434\u043b\u044f \u043c\u043e\u0435\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u044e \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/__\/vi\/rf\/__virfwzlvzvt3fzpnxk-x96ssi.png\"><\/p>\n<h4>Flutter<\/h4>\n<p>  \u0412\u043e Flutter \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u043f\u0443\u0442\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438: <a href=\"https:\/\/flutter.dev\/docs\/codelabs\/explicit-animations\">\u044f\u0432\u043d\u0430\u044f<\/a> \u0438 <a href=\"https:\/\/flutter.dev\/docs\/codelabs\/implicit-animations\">\u043d\u0435\u044f\u0432\u043d\u0430\u044f<\/a>.<\/p>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043b\u043e\u0430\u0434\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u044f\u0432\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e.<\/p>\n<pre><code class=\"dart\">class AnimationExplicitLoader extends StatefulWidget {  @override  State&lt;StatefulWidget&gt; createState() =&gt; _AnimationExplicitLoaderState(); }  class _AnimationExplicitLoaderState extends State&lt;AnimationExplicitLoader&gt;    with SingleTickerProviderStateMixin {  final double _loaderWidth = 100;   AnimationController _controller;   Animation&lt;double&gt; _offsetAnimation;  Animation&lt;double&gt; _opacityAnimation;   @override  void initState() {    super.initState();     final double maxLeft =        (window.physicalSize \/ window.devicePixelRatio).width;     _controller = AnimationController(      duration: const Duration(seconds: 1),      vsync: this,    )..repeat(reverse: true);     _offsetAnimation = Tween&lt;double&gt;(      begin: 0,      end: maxLeft - _loaderWidth,    ).animate(_controller);    _opacityAnimation = Tween&lt;double&gt;(      begin: .8,      end: 1,    ).animate(_controller);  }   @override  void dispose() {    _controller.dispose();    super.dispose();  }   @override  Widget build(BuildContext context) {    return AnimatedBuilder(      animation: _controller,      builder: _buildAnimatedWidget,    );  }   Widget _buildAnimatedWidget(BuildContext context, Widget child) {    return Opacity(      opacity: _opacityAnimation.value,      child: Transform.translate(        offset: Offset(_offsetAnimation.value, 0),        child: Opacity(          opacity: _opacityAnimation.value,          child: Container(            width: _loaderWidth,            height: 5,            color: Colors.white,          ),        ),      ),    );  } } <\/code><\/pre>\n<p>  \u0412\u0441\u0442\u0430\u0432\u0438\u043c \u043b\u043e\u0430\u0434\u0435\u0440 \u0432 AppBar.<\/p>\n<pre><code class=\"dart\">SliverAppBar(  titleSpacing: 0,  backgroundColor: Colors.black.withOpacity(.9),  title: Column(    crossAxisAlignment: CrossAxisAlignment.start,    mainAxisSize: MainAxisSize.min,    children: [      Row(        mainAxisAlignment: MainAxisAlignment.spaceBetween,        children: [          const SizedBox.shrink(),          Text('Title'),          Switch(            value: _isGrid,            onChanged: (bool value) {              setState(() {                _isGrid = value;              });            },          ),        ],      ),      AnimationExplicitLoader(),    ],  ), <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/7r\/1_\/bb\/7r1_bblbji7g7yoegh_lqhetj1c.gif\"><\/p>\n<p>  \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0437\u0430 \u0432\u0440\u0435\u043c\u044f Duration \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043e\u0442 0 \u0434\u043e 1.<\/p>\n<p>  Animation \u2014 \u043a\u043b\u0430\u0441\u0441, \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>  repeat(reverse: true) \u2014 \u0437\u0430\u0446\u0438\u043a\u043b\u0438\u0432\u0430\u0435\u0442 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e.<\/p>\n<p>  \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f setState \u0432 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0435 \u043f\u0440\u0438 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u0430\u0434\u0440\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043d\u043e \u044d\u0442\u043e \u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0435\u0432\u043e.<\/p>\n<p>  AnimatedBuilder \u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c UI, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044f \u043b\u043e\u0433\u0438\u043a\u0443 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c. AnimatedBuilder \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 child \u2014 \u0432\u0438\u0434\u0436\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0438\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u0430\u0434\u0440\u0435.<\/p>\n<p>  \u0420\u0430\u0437\u043c\u0435\u0440\u044b \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u044b \u0432 initState, \u043d\u043e \u0432 \u043d\u0451\u043c \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043c\u0435\u0441\u0442\u043e MediaQuery.of(context).size.width \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0440 \u044d\u043a\u0440\u0430\u043d\u0430 \u0441\u0430\u043c\u0438. \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439 \u0431\u044b\u043b\u043e \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c MediaQuery, \u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0438 \u043f\u0440\u0438\u0441\u0432\u043e\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435 build.<\/p>\n<pre><code class=\"dart\">@override Widget build(BuildContext context) {  if (_controller == null) {    _initAnimation();  }  return AnimatedBuilder(    animation: _controller,    builder: _buildAnimatedWidget,  ); } <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043b\u043e\u0430\u0434\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u043d\u0435\u044f\u0432\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/p>\n<pre><code class=\"dart\">class AnimationImplicitLoader extends StatefulWidget {  @override  State&lt;StatefulWidget&gt; createState() =&gt; _AnimationImplicitLoaderState(); }  class _AnimationImplicitLoaderState extends State&lt;AnimationImplicitLoader&gt; {  static const _duration = Duration(seconds: 1);   final double _loaderWidth = 100;   double _maxLeftCached;   double get _maxLeft =&gt;      _maxLeftCached ??= MediaQuery.of(context).size.width - _loaderWidth;   bool _isStart = false;   @override  void initState() {    super.initState();    SchedulerBinding.instance.addPostFrameCallback((timeStamp) {      setState(() =&gt; _isStart = true);    });  }   @override  Widget build(BuildContext context) {    return SizedBox(      height: 5,      child: Stack(        children: [          AnimatedPositioned(            duration: _duration,            left: _isStart ? 0 : _maxLeft,            onEnd: _onEndAnimation,            child: AnimatedOpacity(              duration: _duration,              opacity: _isStart ? .8 : 1,              child: Container(                width: _loaderWidth,                height: 5,                color: Colors.white,              ),            ),          ),        ],      ),    );  }   void _onEndAnimation() {    setState(() {      _isStart = !_isStart;    });  } } <\/code><\/pre>\n<p>  \u0418 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u0432\u0438\u0434\u0436\u0435\u0442 AnimationImplicitLoader \u0432\u043c\u0435\u0441\u0442\u043e AnimationExplicitLoader.<\/p>\n<p>  \u0412\u0438\u0434\u0436\u0435\u0442\u044b \u043d\u0435\u044f\u0432\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0430\u043d\u0438\u043c\u0438\u0440\u0443\u044e\u0442 \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u043d\u043e\u0432\u044b\u043c\u0438 \u0438 \u0441\u0442\u0430\u0440\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438. \u041d\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f. \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e, \u0432 initState \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c setState.<\/p>\n<p>  \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0431\u0438\u043d\u0434\u0438\u043d\u0433 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 <a href=\"https:\/\/habr.com\/ru\/company\/surfstudio\/blog\/512326\/\">\u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u043c\u043e\u0435\u0433\u043e \u043a\u043e\u043b\u043b\u0435\u0433\u0438 \u041c\u0438\u0448\u0438 \u0417\u043e\u0442\u044c\u0435\u0432\u0430.<\/p>\n<p>  \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0443 \u2014 Future (\u0430\u043d\u0430\u043b\u043e\u0433 Promise \u0438\u0437 JavaScript).<\/p>\n<pre><code class=\"dart\">Future.delayed(_duration).then(  (value) =&gt; setState(() =&gt; _isStart = true), ); <\/code><\/pre>\n<p>  \u0412\u043c\u0435\u0441\u0442\u043e AnimatedPositioned, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 Stack \u0438 \u0431\u044b\u0442\u044c \u043e\u0431\u0451\u0440\u043d\u0443\u0442\u044b\u043c \u0432 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u0432 (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 SizedBox), \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u0432\u0438\u0434\u0436\u0435\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/SlideTransition-class.html\">SlideTransition<\/a> \u2014 \u043d\u043e \u0434\u043b\u044f \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0436\u0435 \u043d\u0443\u0436\u0435\u043d \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440.<\/p>\n<p>  \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/AnimatedPositioned-class.html\">AnimatedPositioned<\/a> \u0438 <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/AnimatedOpacity-class.html\">AnimatedOpacity<\/a>. \u041d\u043e \u0432\u043e Flutter \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e <a href=\"https:\/\/flutter.dev\/docs\/development\/ui\/widgets\/animation\">\u0433\u043e\u0442\u043e\u0432\u044b\u0445<\/a> \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439, \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/AnimatedCrossFade-class.html\">\u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430<\/a> \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u043c\u0438.<\/p>\n<p>  \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0432\u043e Flutter \u043c\u043e\u0436\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430 \u0445\u043e\u0434\u0443.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0442\u0430\u043a\u0443\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043f\u043e\u043b\u043e\u0441\u043a\u0443:<\/p>\n<pre><code class=\"dart\">Tween&lt;double&gt; _opacityTween;  @override void initState() {  super.initState();   final double maxLeft =      (window.physicalSize \/ window.devicePixelRatio).width;   _controller = AnimationController(    duration: const Duration(seconds: 1),    vsync: this,  )..repeat(reverse: true);   _offsetAnimation = Tween&lt;double&gt;(    begin: 0,    end: maxLeft - _loaderWidth,  ).animate(_controller);   _opacityTween = Tween&lt;double&gt;(    begin: .8,    end: 1,  );  _opacityAnimation = _opacityTween.animate(_controller); }  @override void dispose() {  _controller.dispose();  super.dispose(); }  @override Widget build(BuildContext context) {  return GestureDetector(    onTap: () {      _opacityTween.begin = 0;    },    child: AnimatedBuilder(      animation: _controller,      builder: _buildAnimatedWidget,    ),  ); } <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yo\/yh\/rw\/yoyhrwz3hzncmkvovxeeao4g6d0.gif\"><\/p>\n<p>  \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u043c\u044b \u0438\u043c\u0435\u0435\u043c:<br \/>  \u0412 React Native \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u044f\u0432\u043d\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f. \u0412\u043e Flutter \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044f\u0432\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e, \u0434\u0430\u044e\u0449\u0443\u044e \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c, \u0438 \u043d\u0435\u044f\u0432\u043d\u0443\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438 \u0441\u043c\u0435\u043d\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u043e\u043d\u044b\u0439 \u0432\u0438\u0434\u0436\u0435\u0442 SDK. \u041a\u0430\u043a\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0432\u044b\u0431\u0440\u0430\u0442\u044c, \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043d\u0443\u0436\u0435\u043d \u043b\u0438 \u0432\u0430\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<h2>Hero \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f<\/h2>\n<p>  \u0412 React Native \u043d\u0443\u0436\u043d\u043e <a href=\"https:\/\/medium.com\/@nitishprasad\/implementing-shared-element-transition-in-react-native-44c33eb0a82f\">\u043f\u0438\u0441\u0430\u0442\u044c<\/a> \u0435\u0451 \u0441\u0430\u043c\u043e\u043c\u0443. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u0437\u0430\u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442, \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/github.com\/IjzerenHein\/react-native-shared-element\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443<\/a>.<\/p>\n<p>  \u0412\u043e Flutter \u0436\u0435 \u044d\u0442\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 <a href=\"https:\/\/flutter.dev\/docs\/development\/ui\/animations\/hero-animations\">SDK<\/a>. \u041f\u0440\u0430\u0432\u0434\u0430, \u043d\u0435 \u0432\u0441\u0451 \u0442\u0430\u043a \u0433\u043b\u0430\u0434\u043a\u043e. \u0421\u043b\u043e\u0436\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0434\u0442\u043e\u0440\u043c\u0430\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e\u0433\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 <a href=\"https:\/\/flutter.dev\/docs\/perf\/rendering\/shader\">\u043f\u0440\u043e\u0433\u0440\u0435\u0432<\/a>. \u0412\u043e Flutter 1.22 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u0435\u0435, \u0438 \u0432 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043f\u0440\u043e\u0433\u0440\u0435\u0432 \u0443\u0436\u0435 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<h2>\u041e\u0434\u0438\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u2014 \u043e\u0434\u0438\u043d \u043f\u043e\u0442\u043e\u043a<\/h2>\n<p>  \u0412 React Native \u0438 Flutter \u043a\u043e\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441 \u043e\u0434\u043d\u0438\u043c \u043f\u043e\u0442\u043e\u043a\u043e\u043c.<br \/>  \u0412\u0435\u0441\u044c \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043d\u0451\u043c.<\/p>\n<p>  <b>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0432 \u043d\u0430\u0448\u0435\u043c React Native \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u044d\u043c\u0443\u043b\u044f\u0446\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445:<\/b><\/p>\n<pre><code class=\"javascript\">async function getData() {     let count = await new Promise((resolve) =&gt; {         setTimeout(() =&gt; resolve(1000000000), 1000);     })       new Promise(function (resolve) {         let n = 0;         for (let i = 0; i &lt; count; i++) {             n += i;         }         resolve(n);     }) } <\/code><\/pre>\n<p>  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435:<\/p>\n<pre><code class=\"javascript\">useEffect(() =&gt; {     setTimeout(() =&gt; {     setLoading(false)     getData();     }, 3000); }, []); <\/code><\/pre>\n<p>  <\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae15b905dc4e15aeed79e\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15b905dc4e15aeed79e\"><\/iframe><\/div>\n<p>  \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e, \u0438 \u043f\u043e\u043d\u0430\u0447\u0430\u043b\u0443 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 UI \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0435. \u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u2014 \u0432\u0438\u0434\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 Alert. JS \u043f\u043e\u0442\u043e\u043a \u0432\u044b\u0434\u0430\u0451\u0442 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c 55 fps. <\/p>\n<p>  \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0438 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0435 UI \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0442\u044f\u0436\u0451\u043b\u044b\u0439 \u0446\u0438\u043a\u043b: UI \u0431\u043e\u043b\u0435\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d, JS \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u043e\u0441\u0435\u043b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u0421\u043a\u0440\u043e\u043b\u043b\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u044b \u043c\u043e\u0436\u0435\u043c: \u044d\u0442\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 OEM \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b, \u0438 JS \u043f\u043e\u0442\u043e\u043a \u043d\u0430 \u043d\u0435\u0433\u043e \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442. \u041d\u043e \u043a\u043d\u043e\u043f\u043a\u0438 \u043d\u0430 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0435 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u044e\u0442, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0441\u0438\u0433\u043d\u0430\u043b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u0434\u0435\u0442 \u0432 JS \u043f\u043e\u0442\u043e\u043a, \u043e\u0442\u0442\u0443\u0434\u0430 \u0432 \u043c\u043e\u0441\u0442, \u0430 \u043e\u0442\u0442\u0443\u0434\u0430 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443. \u0410 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 JS \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043d\u044f\u0442 \u0446\u0438\u043a\u043b\u043e\u043c, \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u0434\u0440\u0443\u0433\u043e\u0433\u043e.<\/p>\n<p>  \u0414\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c HeadlessJS, \u043d\u043e \u043e\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f Android, \u0430 \u043f\u043e\u0441\u0435\u043c\u0443 \u043d\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u0435\u043d.<\/p>\n<p>  \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u043d\u0430 \u043c\u0435\u043b\u043a\u0438\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"javascript\">async function getData() {    let count = await new Promise((resolve) =&gt; {        setTimeout(() =&gt; resolve(1000000000), 1000);    })      let n = 0;    for(let i = 0; i &lt; count; i++) {        n += await new Promise((res) =&gt; {            setTimeout(() =&gt; {                res(i);            }, 1);        })    }    resolve(n); } <\/code><\/pre>\n<p>  \u041a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0446\u0438\u043a\u043b\u0430 \u043e\u0431\u0451\u0440\u043d\u0443\u0442 \u0432 Promise, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u043f\u043e\u0437\u0436\u0435 \u0438 \u0440\u0430\u0437\u0433\u0440\u0443\u0437\u0438\u0442 \u043f\u043e\u0442\u043e\u043a \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/vf\/vr\/rr\/vfvrrrvs4u1mmvpymuez9o_kjau.gif\"><\/p>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043d\u0430 Flutter.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c Alert \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443:<\/p>\n<pre><code class=\"dart\">for (String name in screenNames)  Padding(    padding: const EdgeInsets.symmetric(horizontal: 5),    child: RaisedButton(      onPressed: () {        showDialog(          context: context,          builder: (_) {            return AlertDialog(              title: Text('\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 Alert'),              actions: [                FlatButton(                  child: Text('OK'),                  onPressed: () {                    Navigator.of(context).pop();                  },                )              ],            );          },        );      },      color: Colors.white,      shape: RoundedRectangleBorder(        borderRadius: BorderRadius.circular(8),      ),      child: Padding(        padding: const EdgeInsets.symmetric(          vertical: 5,          horizontal: 20,        ),        child: Center(          child: Text(name),        ),      ),    ),  ), <\/code><\/pre>\n<p>  \u0418 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"dart\">void getData() async {  final int count = await Future.delayed(const Duration(seconds: 1)).then(    (_) =&gt; 1000000000,  );   Future(() {    int n = 0;    for (int i = 0; i &lt; count; i++) {      n += i;    }    return n;  }); }  Future&lt;List&lt;City&gt;&gt; _getCities() async {  getData();  String json =      await DefaultAssetBundle.of(context).loadString('res\/cities.json');   List&lt;dynamic&gt; data = jsonDecode(json);  List&lt;City&gt; result = [];  data.forEach((city) {    result.add(City(      id: city['id'],      name: city['name'],      image: city['image'],      description: city['description'],      places: city['places'],    ));  });  return result; } <\/code><\/pre>\n<p>  <\/p>\n<div class=\"oembed\"><iframe id=\"5f9ae15b3b295d140fdb3884\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15b3b295d140fdb3884\"><\/iframe><\/div>\n<p>  \u041c\u044b \u0432\u0438\u0434\u0438\u043c \u0442\u0435 \u0436\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 \u043e\u0442\u0437\u044b\u0432\u0447\u0438\u0432\u043e\u0441\u0442\u044c\u044e UI. \u041f\u043e\u0447\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u2014 \u0447\u0435\u0440\u0435\u0437 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c:<\/p>\n<pre><code class=\"dart\">void getData() async {  final int count = await Future.delayed(const Duration(seconds: 1)).then(    (_) =&gt; 1000000000,  );   Future(() async {    int n = 0;    for(int i = 0; i &lt; count; i++) {      n += await Future(() {        return i;      });    }    return n;  });  } <\/code><\/pre>\n<p>  \u041d\u043e \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u043b\u043e\u0433\u0438\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c. \u0420\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u0435\u0451 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0447\u0430\u0441\u0442\u0438 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043f\u043e\u0442\u043e\u043a.<\/p>\n<p>  JSON \u0434\u043b\u044f JS \u2014 \u044d\u0442\u043e \u0440\u043e\u0434\u043d\u044b\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b: \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0441 \u043d\u0438\u043c\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u0435\u0441\u0442\u044c. \u0414\u043b\u044f Dart \u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u043f\u0435\u0440\u0432\u0430 \u0435\u0433\u043e \u0440\u0430\u0441\u043f\u0430\u0440\u0441\u0438\u0442\u044c. \u042d\u0442\u043e \u0437\u0430\u0439\u043c\u0451\u0442 \u0432\u0440\u0435\u043c\u044f \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0430 \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043b\u043e\u0433\u0438\u043a\u0443 \u043d\u0435 \u0440\u0430\u0437\u043e\u0431\u044c\u0435\u0448\u044c \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u043c\u0435\u043b\u043a\u0438\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>  \u0422\u044f\u0436\u0451\u043b\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u044c, \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 UI \u043f\u043e\u0442\u043e\u043a. \u0412 React Native \u0441 \u044d\u0442\u0438\u043c \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043c\u0438\u0440\u0438\u0442\u044c\u0441\u044f, \u0432 Dart \u0436\u0435 \u0435\u0441\u0442\u044c \u0438\u0437\u043e\u043b\u044f\u0442\u044b.<\/p>\n<p>  \u0418\u0437\u043e\u043b\u044f\u0442 \u2014 \u044d\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u043e \u0441\u0432\u043e\u0435\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u044c\u044e \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u043f\u043e\u0442\u043e\u043a\u043e\u043c.<\/p>\n<p>  \u041d\u043e\u0432\u044b\u0439 \u0438\u0437\u043e\u043b\u044f\u0442 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f UI.<\/p>\n<p>  \u041f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u043b\u044f\u0442\u0430:<\/p>\n<pre><code class=\"dart\">Future&lt;List&lt;City&gt;&gt; _getCities() async {    String json =        await DefaultAssetBundle.of(context).loadString('res\/cities.json');     List&lt;dynamic&gt; data = jsonDecode(json);    List&lt;City&gt; result = await compute(_handleData, data);     return result;  } } \/\/ \u041a\u043e\u043d\u0435\u0446 \u0432\u0438\u0434\u0436\u0435\u0442\u0430  Future&lt;int&gt; getData() async {  final int count = await Future.delayed(const Duration(seconds: 1)).then(        (_) =&gt; 1000000000,  );   int n = 0;  for (int i = 0; i &lt; count; i++) {    n += i;  }  return n;  }  List&lt;City&gt; _handleData(data) {  getData();  List&lt;City&gt; result = [];  data.forEach((city) {    result.add(City(      id: city['id'],      name: city['name'],      image: city['image'],      description: city['description'],      places: city['places'],    ));  });  return result; } <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/-l\/ti\/um\/-ltiumnbrfujbgs2lnwopeczmhq.gif\"><\/p>\n<p>  compute \u2014 \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u0437\u043e\u043b\u044f\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u0451\u0442, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442, \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442.<\/p>\n<p>  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0438\u0437\u043e\u043b\u044f\u0442, \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u0442\u0430\u0440\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0437\u0431\u0438\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0432\u043e Future.<br \/>  \u0426\u0438\u043a\u043b \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435 \u043f\u043e\u0432\u0435\u0441\u0438\u0442 \u043f\u043e\u0442\u043e\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0438\u0437\u043e\u043b\u044f\u0442\u0430, \u043d\u0435 \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u0432 \u0434\u0440\u0443\u0433\u0438\u0435.<\/p>\n<p>  \u041c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c compute \u0434\u043b\u044f \u0440\u0435\u0434\u043a\u0438\u0445 \u0442\u044f\u0436\u0451\u043b\u044b\u0445 \u043a\u0435\u0439\u0441\u043e\u0432 \u0438\u043b\u0438 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c\u0438 \u043d\u0443\u0436\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043e\u043b\u044f\u0442\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439.<\/p>\n<h2>\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f<\/h2>\n<p>  <\/p>\n<h4>React Native<\/h4>\n<p>  \u041e\u0434\u043d\u0430 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c React Native \u2014 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f. SDK \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d\u0435.<\/p>\n<p>  \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f <a href=\"https:\/\/reactnative.dev\/docs\/navigation\">\u0441\u043e\u0432\u0435\u0442\u0443\u0435\u0442<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043e\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430 <a href=\"https:\/\/reactnavigation.org\/\">React Navigation<\/a>. \u0415\u0451 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u2014 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0438 \u0431\u0435\u0441\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438. \u041d\u043e \u043b\u043e\u0433\u0438\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432 JS \u043f\u043e\u0442\u043e\u043a\u0435.<\/p>\n<p>  \u0425\u043e\u0440\u043e\u0448\u0430\u044f \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u2014 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u043e\u0442 WIX: <a href=\"https:\/\/github.com\/wix\/react-native-navigation\">React Native Navigation<\/a>. \u0415\u0451 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u2014 \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435. \u041c\u0438\u043d\u0443\u0441 \u2014 \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 Redux. \u041c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u043c\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u0434.<\/p>\n<p>  \u0411\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <a href=\"https:\/\/www.arrowhitech.com\/react-navigation-vs-react-native-navigation-the-complete-comparison\/\">\u0441\u0442\u0430\u0442\u044c\u0435 \u00abReact Navigation vs React Native Navigation: The complete comparison\u00bb<\/a>.<\/p>\n<p>  \u0412 React Native \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438. \u0415\u0441\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043d\u043e \u044d\u0442\u0438 \u2014 \u0441\u0430\u043c\u044b\u0435 \u0433\u043b\u0430\u0432\u043d\u044b\u0435, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434. <\/p>\n<p>  \u0412\u044b\u0431\u043e\u0440 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0446\u0435\u043b\u0435\u0439:<br \/>  \u041d\u0443\u0436\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u2014 React Navigation.<br \/>  \u041d\u0443\u0436\u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u2014 React Native Navigation.<\/p>\n<p>  \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u044b\u0431\u043e\u0440, \u043d\u043e \u043d\u0435\u0442 \u0446\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0434\u0430\u0432\u0430\u043b\u043e \u0431\u044b \u043d\u0430\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0443, \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u044b \u043b\u0438\u0431\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c JS \u043f\u043e\u0442\u043e\u043a, \u043b\u0438\u0431\u043e OEM \u0441\u043b\u043e\u0439.<\/p>\n<h4>Flutter<\/h4>\n<p>  \u0412\u043e Flutter \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. \u041d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u044b. \u0414\u043b\u044f Flutter \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u043e \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438, \u043d\u043e \u043e\u043d\u0438 \u0431\u0430\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0430 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u0435\u0451 \u0441 \u043d\u0443\u043b\u044f. \u041d\u043e \u0438 \u0431\u0435\u0437 \u043d\u0438\u0445 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430 \u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445.<\/p>\n<p>  \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  1. <a href=\"https:\/\/flutter.dev\/docs\/cookbook\/navigation\/navigation-basics\">\u041f\u0435\u0440\u0435\u0445\u043e\u0434<\/a> \u043d\u0430 \u044d\u043a\u0440\u0430\u043d \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e:<\/p>\n<pre><code class=\"dart\">onPressed: () {   Navigator.push(     context,     MaterialPageRoute(builder: (context) =&gt; SecondRoute()),   ); } <\/code><\/pre>\n<p>  \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442. \u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0438 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0432 \u043d\u0435\u0433\u043e \u0432\u0438\u0434\u0436\u0435\u0442 \u044d\u043a\u0440\u0430\u043d\u0430 SecondRoute.<\/p>\n<p>  \u041c\u043e\u0436\u043d\u043e \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044f\u0432\u043d\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440:<\/p>\n<p>  Material<\/p>\n<pre><code class=\"dart\">class CitiesScreenRoute extends MaterialPageRoute {  CitiesScreenRoute()      : super(          builder: (ctx) =&gt; CitiesScreen(),        ); } <\/code><\/pre>\n<p>  Cupertino<\/p>\n<pre><code class=\"dart\">class CitiesScreenRoute extends CupertinoPageRoute {  CitiesScreenRoute()      : super(          builder: (ctx) =&gt; CitiesScreen(),        ); } <\/code><\/pre>\n<p>  2. <a href=\"https:\/\/flutter.dev\/docs\/cookbook\/navigation\/named-routes\">\u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0439<\/a> \u043c\u0430\u0440\u0448\u0440\u0443\u0442:<\/p>\n<pre><code class=\"dart\">MaterialApp(   \/\/ Start the app with the &quot;\/&quot; named route. In this case, the app starts   \/\/ on the FirstScreen widget.   initialRoute: '\/',   routes: {     \/\/ When navigating to the &quot;\/&quot; route, build the FirstScreen widget.     '\/': (context) =&gt; FirstScreen(),     \/\/ When navigating to the &quot;\/second&quot; route, build the SecondScreen widget.     '\/second': (context) =&gt; SecondScreen(),   }, ); <\/code><\/pre>\n<p>  \u0412 \u0432\u0435\u0440\u0441\u0438\u0438 Flutter 1.22 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438: Navigator 2 \u0441 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c:<\/p>\n<pre><code class=\"dart\">Navigator(  key: navigatorKey,  pages: [    MaterialPage(      key: ValueKey('BooksListPage'),      child: BooksListScreen(        books: books,        onTapped: _handleBookTapped,      ),    ),    if (show404)      MaterialPage(key: ValueKey('UnknownPage'), child: UnknownScreen())    else if (_selectedBook != null)      BookDetailsPage(book: _selectedBook)  ],  onPopPage: (route, result) {    if (!route.didPop(result)) {      return false;    }     \/\/ Update the list of pages by setting _selectedBook to null    _selectedBook = null;    show404 = false;    notifyListeners();     return true;  }, ) <\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u043d\u0430\u0432\u0438\u0433\u0430\u0442\u043e\u0440 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438: \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438\u0437 \u0441\u0442\u044d\u043a\u0430.<\/p>\n<p>  \u041f\u0440\u0435\u0436\u043d\u044e\u044e \u0438\u043c\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u0443\u044e \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044e \u0442\u043e\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043d\u043e\u0432\u043e\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441\u043e \u0441\u0442\u0430\u0440\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432 <a href=\"https:\/\/medium.com\/flutter\/learning-flutters-new-navigation-and-routing-system-7c9068155ade\">\u0441\u0442\u0430\u0442\u044c\u0435 \u00abLearning Flutter\u2019s new navigation and routing system\u00bb<\/a>.<\/p>\n<h2>Overlay<\/h2>\n<p>  <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/Overlay-class.html\">Overlay<\/a> \u2014 \u044d\u0442\u043e \u0441\u0442\u0435\u043a \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u043f\u043e\u0432\u0435\u0440\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432. \u041e\u043d\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430.<\/p>\n<p>  \u0421\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 Overlay \u043d\u0435 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u043f\u0440\u0438 \u043d\u0430\u0441\u043b\u043e\u0435\u043d\u0438\u0438 \u2014 \u043e\u043d\u0438 \u0442\u0430\u043a \u0436\u0435 \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f.<\/p>\n<p>  \u0412\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u0436\u0435\u0442\u044b, \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u043d\u0435\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u0439 Container \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u0439 \u0432\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e, \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u0432\u0438\u0434\u0435\u043d, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u0434 \u043d\u0438\u043c.<\/p>\n<p>  \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u044b \u043f\u043e\u0432\u0435\u0440\u0445 \u0434\u0440\u0443\u0433\u0438\u0445, <a href=\"https:\/\/medium.com\/saugo360\/https-medium-com-saugo360-flutter-using-overlay-to-display-floating-widgets-2e6d0e8decb9\">\u0441\u0442\u0440\u043e\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 UI<\/a>.<\/p>\n<p>  \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Overlay:  <\/p>\n<ul>\n<li>\u0412\u0438\u0434\u0436\u0435\u0442 \u0436\u0438\u0432\u0451\u0442 \u043d\u0435 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u043a\u0440\u0430\u043d\u0430, \u0430 \u0432 \u0441\u0432\u043e\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0441\u043b\u043e\u0435.<\/li>\n<li>\u0420\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u0432 Overlay \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0442 \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430.<\/li>\n<li>\u041d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u044d\u043a\u0440\u0430\u043d\u0443, \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432.<\/li>\n<\/ul>\n<p>  \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0432\u043e\u0438\u043c \u0443\u0447\u0430\u0441\u0442\u0438\u0435\u043c \u0432 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e OverlayEntry.<\/p>\n<p>  Navigator.of(context) \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 NavigatorState. \u0415\u0441\u043b\u0438 \u043c\u044b \u043e\u0442\u043a\u0440\u043e\u0435\u043c \u0435\u0433\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434, \u0442\u043e \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 build \u0443\u0432\u0438\u0434\u0438\u043c:<\/p>\n<pre><code class=\"dart\">@override Widget build(BuildContext context) {  assert(!_debugLocked);  assert(_history.isNotEmpty);  \/\/ Hides the HeroControllerScope for the widget subtree so that the other  \/\/ nested navigator underneath will not pick up the hero controller above  \/\/ this level.  return HeroControllerScope(    child: Listener(      onPointerDown: _handlePointerDown,      onPointerUp: _handlePointerUpOrCancel,      onPointerCancel: _handlePointerUpOrCancel,      child: AbsorbPointer(        absorbing: false, \/\/ it's mutated directly by _cancelActivePointers above        child: FocusScope(          node: focusScopeNode,          autofocus: true,          child: Overlay(            key: _overlayKey,            initialEntries: overlay == null ?                _allRouteOverlayEntries.toList(growable: false)               : const &lt;OverlayEntry&gt;[],          ),        ),      ),    ),  ); } <\/code><\/pre>\n<p>  \u041d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0430 child: Overlay.<\/p>\n<p>  \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043d\u0430\u0432\u0438\u0433\u0430\u0442\u043e\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u0435\u043c \u0441\u0432\u043e\u0438\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432.<\/p>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u0438\u0431\u0438\u0442\u044b\u0439 \u043a \u043d\u0438\u0437\u0443 \u0431\u043b\u043e\u043a \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Overlay:<\/p>\n<pre><code class=\"dart\">bool _overlayFlag = true;  OverlayEntry _entry; Timer timer;  @override void initState() {  super.initState();   timer = Timer.periodic(const Duration(seconds: 3), (timer) {    _overlayFlag = !_overlayFlag;    _entry.markNeedsBuild();  });   SchedulerBinding.instance.addPostFrameCallback((timeStamp) {    _entry = OverlayEntry(builder: (context) {      return Positioned(        bottom: 10,        left: 0,        right: 0,        child: Material(          type: MaterialType.transparency,          child: Center(            child: AnimatedContainer(              decoration: BoxDecoration(                color: _overlayFlag ? Colors.black : Colors.white,                boxShadow: [                  BoxShadow(                    blurRadius: 10,                    color: _overlayFlag ? Colors.white : Colors.black,                  ),                ],              ),              duration: const Duration(milliseconds: 500),              child: Padding(                padding: const EdgeInsets.symmetric(                  vertical: 50,                  horizontal: 100,                ),                child: Text(                  '\u041f\u043b\u0430\u0432\u0430\u044e\u0449\u0430\u044f \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430',                  style: TextStyle(                    color: _overlayFlag ? Colors.white : Colors.black,                  ),                ),              ),            ),          ),        ),      );    });    Overlay.of(context).insert(_entry);  }); }  @override void dispose() {  _entry?.remove();  timer?.cancel();  super.dispose(); } <\/code><\/pre>\n<div class=\"oembed\"><iframe id=\"5f9ae15b017bf613f0899da9\" src=\"https:\/\/embedd.srv.habr.com\/iframe\/5f9ae15b017bf613f0899da9\"><\/iframe><\/div>\n<p>  _entry \u2014 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 OverlayEntry.<br \/>  timer \u2014 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 Timer.<\/p>\n<p>  \u0412 initState \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 OverlayEntry. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0444\u043b\u0430\u0433\u0430 _overlayFlag \u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0446\u0432\u0435\u0442\u0430.<\/p>\n<p>  Overlay.of(context) \u2014 \u043d\u0430\u0445\u043e\u0434\u0438\u043c Overlay, \u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0430\u0448\u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 insert \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 entry \u0432 \u0441\u0442\u044d\u043a \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0422\u0430\u0439\u043c\u0435\u0440 \u043a\u0430\u0436\u0434\u044b\u0435 3 \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u043c\u0435\u043d\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 _overlayFlag. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f _entry.markNeedsBuild() \u2014 \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u043e\u0432\u0435\u0441\u0442\u0438\u0442\u044c entry \u0438 \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u043b \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f. \u0422\u0430\u043a \u043a\u0430\u043a \u0432\u0438\u0434\u0436\u0435\u0442 \u0432 \u0441\u0442\u044d\u043a\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445, \u0442\u043e \u044d\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u0442\u043e\u0433\u043e \u0432\u0438\u0434\u0436\u0435\u0442\u0430, \u0433\u0434\u0435 \u043e\u043d \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d. \u0421\u043c\u0435\u043d\u0430 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e State \u043d\u0430 \u043d\u0435\u0433\u043e \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0436\u0435 \u0432\u0430\u043c \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0432\u0435\u0440\u043b\u0435\u044f\u043c\u0438 \u0432 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435, \u0442\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u044d\u0442\u0430 <a href=\"https:\/\/pub.dev\/packages\/flutter_portal\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430<\/a>.<\/p>\n<h2>\u0412\u0435\u0440\u0434\u0438\u043a\u0442<\/h2>\n<p>  \u0421 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f UI, <b>React Native<\/b> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u0443\u044e \u043a\u043e\u0434\u043e\u0432\u0443\u044e \u0431\u0430\u0437\u0443 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445. \u042d\u0442\u043e \u043a\u0430\u0440\u043a\u0430\u0441, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u2014 \u043d\u043e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>  \u0418\u0437-\u0437\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 OEM \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432, \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u0443\u0437\u043a\u0438\u0445 \u043c\u0435\u0441\u0442 \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b.<\/p>\n<p>  <b>Flutter<\/b> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 SDK \u0441 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u043c\u0438 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438. \u0421\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f UI \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0435 \u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432, Flutter \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043d \u0437\u0430\u043f\u0443\u0449\u0435\u043d, \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c.<\/p>\n<p>  \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u043c \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 React Native \u0438 Flutter: \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439, \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b, \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<blockquote><p>Surf \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u043d\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e Flutter. \u041a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0441\u0432\u043e\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044e \u0438 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u043d\u0430\u0434 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438. \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u0441 \u0443\u043f\u043e\u0440\u043e\u043c \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0443, \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 Surf \u0434\u0430\u044e\u0442 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430\u043c \u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438.<\/p>\n<p>  <a href=\"https:\/\/education.surf.ru\/\">\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043a\u0443\u0440\u0441\u0430 \u043f\u043e Flutter<\/a><\/p>\n<p>  <a href=\"https:\/\/habr.com\/ru\/company\/surfstudio\/blog\/525598\/\">\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043e \u043a\u0443\u0440\u0441\u0435 \u0438 \u0443\u0447\u0435\u0431\u043d\u043e\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435<\/a><\/p><\/blockquote>\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\/company\/surfstudio\/blog\/525688\/\"> https:\/\/habr.com\/ru\/company\/surfstudio\/blog\/525688\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0414\u043c\u0438\u0442\u0440\u0438\u0439 \u0410\u043d\u0434\u0440\u0438\u044f\u043d\u043e\u0432. \u0414\u0432\u0430 \u0433\u043e\u0434\u0430 \u044f \u043f\u0438\u0441\u0430\u043b \u043d\u0430 React Native, \u0441\u0435\u0439\u0447\u0430\u0441 \u0440\u0430\u0431\u043e\u0442\u0430\u044e <a href=\"https:\/\/surf.ru\/\">\u0432 Surf<\/a> \u0432\u043e <a href=\"https:\/\/surf.ru\/flutter\/\">Flutter \u043e\u0442\u0434\u0435\u043b\u0435<\/a> \u0438 \u0443\u0436\u0435 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0443\u0442\u043e\u0440\u0430 \u043b\u0435\u0442 \u043f\u0438\u0448\u0443 \u043d\u0430 Flutter.<\/p>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/surfstudio\/blog\/511330\/\">\u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a> \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b \u043f\u0440\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0435\u0436\u0434\u0443 React Native \u0438 Flutter.<br \/>  \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u043c\u0435\u0436\u0434\u0443 React Native \u0438 Flutter \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 UI \u0434\u043b\u044f Android \u0438 iOS.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/2g\/yo\/sn\/2gyosnwbfcro12wdfgqjgfrnfio.png\">  <\/p>\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-312496","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/312496","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=312496"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/312496\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=312496"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=312496"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=312496"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}