{"id":344297,"date":"2023-01-22T09:00:44","date_gmt":"2023-01-22T09:00:44","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=344297"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=344297","title":{"rendered":"<span>\u0418\u0437\u0443\u0447\u0430\u0435\u043c Reanimated 2 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u044f \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>React Native \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 Animated API \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0447\u0430\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u043b\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0438\u00a0\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438\u00a0\u043d\u0430 60 fps, \u0431\u0435\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e Reanimated 2 \u0438 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5ae\/0e5\/f2f\/5ae0e5f2f8d9e71724b333d7b419eb76.gif\" alt=\"\u0418\u0434\u0435\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 https:\/\/dribbble.com\/shots\/3368130-Stepper-Touch\" title=\"\u0418\u0434\u0435\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 https:\/\/dribbble.com\/shots\/3368130-Stepper-Touch\" width=\"600\" height=\"450\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5ae\/0e5\/f2f\/5ae0e5f2f8d9e71724b333d7b419eb76.gif\"\/><figcaption>\u0418\u0434\u0435\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 https:\/\/dribbble.com\/shots\/3368130-Stepper-Touch<\/figcaption><\/figure>\n<h2>Reanimated<\/h2>\n<p>\u0417\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438\u00a0\u0432 React Native \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <a href=\"https:\/\/reactnative.dev\/docs\/animated\" rel=\"noopener noreferrer nofollow\">Animated API<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432. \u041e\u0434\u043d\u0430\u043a\u043e \u0443 \u043d\u0435\u0433\u043e \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 &#8212; \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 JS \u043f\u043e\u0442\u043e\u043a\u0435 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u044c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u0430 \u043d\u0430 UI \u043f\u043e\u0442\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>useNativeDriver<\/code><\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u043e\u0431\u0445\u043e\u0434\u0430 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u044b Software Mansion \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/docs.swmansion.com\/react-native-reanimated\/\" rel=\"noopener noreferrer nofollow\">Reanimated<\/a> \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435-\u0444\u0430\u043a\u0442\u043e \u0441\u0442\u0430\u043b\u0430 \u0441\u0430\u043c\u044b\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0432 React Native.\u00a0\u0427\u0442\u043e\u0431\u044b \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c JS \u043f\u043e\u0442\u043e\u043a \u043e\u0442 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 Reanimated \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 JS \u043f\u043e\u0442\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u042d\u0442\u043e \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0438 \u0432\u0432\u043e\u0434\u0438\u0442 2 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 <strong>Worklets<\/strong> \u0438 <strong>Shared Values<\/strong>.<\/p>\n<h2>Worklets<\/h2>\n<p>\u0412\u043e\u0440\u043a\u043b\u0435\u0442\u044b\u00a0\u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u0445 Reanimated \u044d\u0442\u043e\u00a0\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435\u00a0JS \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f\u00a0\u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c JS \u043f\u043e\u0442\u043e\u043a\u0435 \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439.\u00a0\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e\u00a0\u043d\u0443\u0436\u043d\u043e \u0447\u0442\u043e\u0431\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0442\u0430\u043b\u0430\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u043c\u00a0\u044d\u0442\u043e \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u043e\u0439 <code>worklet<\/code><\/p>\n<pre><code class=\"javascript\">function someWorklet(greeting) {   'worklet';   console.log(\"Hey I'm running on the UI thread\"); }<\/code><\/pre>\n<p>\u0412\u043e\u0440\u043a\u043b\u0435\u0442\u044b \u0442\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c JS. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c JS \u043f\u043e\u0442\u043e\u043a\u0435. \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u043e\u0440\u043a\u043b\u0435\u0442. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0430.<\/p>\n<pre><code class=\"javascript\">const width = 135.5;  function otherWorklet(greeting) {   'worklet';   console.log(greeting, 'From the UI thread');   console.log('Captured width is', width); }<\/code><\/pre>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 React Native \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>runOnJS<\/code><\/p>\n<pre><code class=\"javascript\">function callback(text) {   console.log('Running on the RN thread', text); }  function someWorklet() {   'worklet';   console.log(\"I'm on UI but can call methods from the RN thread\");   runOnJS(callback)('can pass arguments too'); }<\/code><\/pre>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u044b \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0435 \u0447\u0430\u0441\u0442\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u0443\u043a\u043e\u0432 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u044b.<\/p>\n<h2>Shared values<\/h2>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043e\u0434\u043d\u0438\u0445 \u0442\u043e\u043b\u044c\u043a\u043e\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u0432\u00a0\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0436\u043d\u043e\u0439 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f Shared values. \u041e\u043d\u0438 \u0440\u0435\u0448\u0430\u044e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c,\u00a0\u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445\u00a0\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u00a0\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u00a0\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u043c\u044f\u0442\u0438 \u0434\u043b\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 JS \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u0412\u0442\u043e\u0440\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u044d\u0442\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c, Reanimated \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u0440\u0430\u0444 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 Shared values \u0438\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u0430\u043c\u0438\u00a0\u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f. \u0414\u0430\u043b\u0435\u0435 \u0435\u0441\u043b\u0438\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u00a0\u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043b\u0438 \u043a\u043e\u0433\u0434\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f shared value \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0435 \u0441 \u044d\u0442\u0438\u043c\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u043c.<\/p>\n<pre><code class=\"javascript\">import Animated, {   useSharedValue,   useAnimatedStyle, } from 'react-native-reanimated';  function Box() {   const offset = useSharedValue(0);    const animatedStyles = useAnimatedStyle(() => {     return {       transform: [{ translateX: offset.value }],     };   });    return (     &lt;>       &lt;Animated.View style={[styles.box, animatedStyles]} \/>       &lt;Button onPress={() => (offset.value = Math.random() * 255)} title=\"Move\" \/>     &lt;\/>   ); }<\/code><\/pre>\n<p><code>useAnimatedStyle<\/code> \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u00a0\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f\u00a0\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00a0<code>offset.value<\/code> \u0441\u0442\u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u0422\u0440\u0435\u0442\u044c\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435 <code>View<\/code> \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e, \u043d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u044d\u0442\u043e \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 <code>shared values<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e time-based\u00a0\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439.\u00a0\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438\u00a0\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>withSpring<\/code><\/p>\n<pre><code class=\"javascript\">&lt;Button   onPress={() => {     offset.value = withSpring(Math.random() * 255);   }}   title=\"Move\" \/><\/code><\/pre>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Reanimated <\/h2>\n<p>\u0411\u0435\u0437 \u0443\u0447\u0435\u0442\u0430 \u0441\u0442\u0438\u043b\u0435\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0432 70 \u0441\u0442\u0440\u043e\u043a. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0435\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {useState} from 'react'; import {Gesture, GestureDetector} from 'react-native-gesture-handler' import MaskedView from '@react-native-masked-view\/masked-view'; import Animated, {     withSequence,     useAnimatedStyle,     useSharedValue,     withSpring,     runOnJS, } from 'react-native-reanimated'; import {StyleSheet, Text, View} from \"react-native\";  const Counter = ({initValue = 0}) => {     const [value, setValue] = useState(initValue)          const offset = useSharedValue(0);     const minusScale = useSharedValue(1);     const plusScale = useSharedValue(1);      const ballAnimatedStyles = useAnimatedStyle(() => ({         transform: [{translateX: offset.value }]     }));     const minusAnimatedStyles = useAnimatedStyle(() => ({         transform: [{scale: minusScale.value }]     }));     const plusAnimatedStyles = useAnimatedStyle(() => ({         transform: [{scale: plusScale.value }]     }));      const tap = Gesture.Pan().onUpdate(e => {         if (e.translationX > 0 &amp;&amp; e.translationX &lt; 75) {             offset.value = e.translationX         } else if (value > 0 &amp;&amp; e.translationX > -75  &amp;&amp; e.translationX &lt; 0) {             offset.value = e.translationX         } else if (value === 0 &amp;&amp; e.translationX > -25  &amp;&amp; e.translationX &lt; 0) {             offset.value = e.translationX         }     }).onEnd((e) => {         offset.value = withSpring(0)          if (e.translationX > 30) {             plusScale.value = withSequence(withSpring(1.2), withSpring(1))             runOnJS(setValue)(value + 1)         }         if (e.translationX &lt; -30 &amp;&amp; value > 0) {             minusScale.value = withSequence(withSpring(1.2), withSpring(1))             runOnJS(setValue)(value - 1)         }         if (e.translationX &lt; 0 &amp;&amp; value === 0) {             minusScale.value = withSequence(withSpring(1.2), withSpring(1))         }     })      return &lt;MaskedView       style={styles.maskContainer}       androidRenderingMode=\"software\"       maskElement={&lt;View style={styles.maskElementContainer} \/>}     >         &lt;View style={[styles.controlContainer]}>             &lt;Animated.View style={[styles.leftContainer, minusAnimatedStyles]}>                 &lt;Text style={[styles.minusText, ...value &lt;= 0 ? [styles.disabledText] : [] ]}>-&lt;\/Text>             &lt;\/Animated.View>             &lt;GestureDetector gesture={tap}>                 &lt;Animated.View style={[styles.ballContainer, ballAnimatedStyles]}>                     &lt;Text style={styles.counterText}>{value}&lt;\/Text>                 &lt;\/Animated.View>             &lt;\/GestureDetector>             &lt;Animated.View style={[styles.rightContainer, plusAnimatedStyles]}>                 &lt;Text style={styles.signText}>+&lt;\/Text>             &lt;\/Animated.View>         &lt;\/View>     &lt;\/MaskedView> }  const styles = StyleSheet.create({     maskContainer: {         width: 180,         height: 80,     },     maskElementContainer: {         width: 180,         height: 80,         borderRadius: 40,         backgroundColor: '#7775ff',         zIndex: 0     },     controlContainer: {         flexDirection: 'row',         alignItems: 'center',         justifyContent: 'space-between',         width: 180,         height: 80,         borderRadius: 40,         backgroundColor: '#7775ff',     },     ballContainer: {         alignItems: 'center',         justifyContent: 'center',         width: 80,         height: 80,         borderRadius: 40,         backgroundColor: '#fff',         zIndex: 20     },     signText: {         fontSize: 36,         color: '#fff',         fontFamily: 'monospace',     },     minusText: {         fontSize: 36,         color: '#fff',         fontFamily: 'monospace',     },     disabledText: {         color: 'rgba(256, 256, 256, 0.4)',     },     leftContainer: {         flex: 1,         alignItems: 'center',     },     rightContainer: {         flex: 1,         alignItems: 'center',     },     counterText: {         fontSize: 36,         color: '#7775ff',         fontFamily: 'monospace',         fontWeight: 'bold'     }, });  export default Counter <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e Reanimated \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f <a href=\"https:\/\/docs.swmansion.com\/react-native-gesture-handler\/\" rel=\"noopener noreferrer nofollow\">Gesture Handler<\/a> \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0430\u0441\u043a\u0438 <a href=\"https:\/\/github.com\/react-native-masked-view\/masked-view\" rel=\"noopener noreferrer nofollow\">Masked View<\/a>.<\/p>\n<pre><code class=\"javascript\">&lt;MaskedView       style={styles.maskContainer}       androidRenderingMode=\"software\"       maskElement={&lt;View style={styles.maskElementContainer} \/>}     >         &lt;View style={[styles.controlContainer]}>             &lt;Animated.View style={[styles.leftContainer, minusAnimatedStyles]}>                 &lt;Text style={[styles.minusText, ...value &lt;= 0 ? [styles.disabledText] : [] ]}>-&lt;\/Text>             &lt;\/Animated.View>             &lt;GestureDetector gesture={tap}>                 &lt;Animated.View style={[styles.ballContainer, ballAnimatedStyles]}>                     &lt;Text style={styles.counterText}>{value}&lt;\/Text>                 &lt;\/Animated.View>             &lt;\/GestureDetector>             &lt;Animated.View style={[styles.rightContainer, plusAnimatedStyles]}>                 &lt;Text style={styles.signText}>+&lt;\/Text>             &lt;\/Animated.View>         &lt;\/View> &lt;\/MaskedView><\/code><\/pre>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 <code>MaskedView<\/code> \u0438 \u0442\u0440\u0435\u0445 <code>Animated.View<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c &#8212; \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u043a\u0438 \u043f\u043b\u044e\u0441\u0430 \u0438 \u043c\u0438\u043d\u0443\u0441\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0438. \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0436\u0435\u0441\u0442\u0430 \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>GestureDetector<\/code>.<\/p>\n<pre><code class=\"javascript\">\/\/ ... const offset = useSharedValue(0);  const ballAnimatedStyles = useAnimatedStyle(() => ({   transform: [{translateX: offset.value }] })); \/\/ ... const tap = Gesture.Pan().onUpdate(e => {     if (e.translationX > 0 &amp;&amp; e.translationX &lt; 75) {         offset.value = e.translationX     } else if (value > 0 &amp;&amp; e.translationX > -75  &amp;&amp; e.translationX &lt; 0) {         offset.value = e.translationX     } }).onEnd((e) => {     offset.value = withSpring(0)      if (e.translationX > 30) {         runOnJS(setValue)(value + 1)     }     if (e.translationX &lt; -30 &amp;&amp; value > 0) {         runOnJS(setValue)(value - 1)     } }) \/\/ ... &lt;GestureDetector gesture={tap}>   &lt;Animated.View style={[styles.ballContainer, ballAnimatedStyles]}>      &lt;Text style={styles.counterText}>{value}&lt;\/Text>   &lt;\/Animated.View> &lt;\/GestureDetector> \/\/ ...<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430\u00a0\u0430\u043d\u0438\u043c\u0438\u0440\u0443\u0435\u043c\u00a0\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c <code>shared value<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0439  \u0431\u0443\u0434\u0435\u043c \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440\u0430 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0422\u0430\u043a \u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0445\u0443\u043a <code>useAnimatedStyle<\/code> \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0439 \u0430\u0441\u0441\u043e\u0446\u0438\u0430\u0446\u0438\u044e \u043c\u0435\u0436\u0434\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>shared value<\/code> \u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 View \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0435\u0433\u043e \u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u0443\u0435\u043c. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u043e \u043e\u0441\u0438 X \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432\u043e <code>View<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u00a0<code>style<\/code>. \u0412 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u043a\u0430\u0441\u0430\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f 2 \u043c\u0435\u0442\u043e\u0434\u0430 onUpdate \u0438 <code>onEnd<\/code>. \u0412 <code>onUpdate<\/code> \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u043e\u0441\u0438 X \u0438\u00a0\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u00a0\u043c\u0435\u043d\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>shared value<\/code>\u00a0\u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e\u00a0\u0441 <code>useAnimatedStyle<\/code>\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u043c. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>onEnd<\/code> \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0436\u0435\u0441\u0442\u0430, \u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 withSpring \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>shared value<\/code>\u00a0\u0432 0 \u0430 \u0442\u0430\u043a \u0436\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0438\u043b\u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0430. \u0412\u0430\u0436\u043d\u043e \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>runOnJS<\/code> \u0442\u0430\u043a \u043a\u0430\u043a <code>GestureDetector<\/code> \u0442\u0430\u043a \u0436\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043d\u0430 UI \u043f\u043e\u0442\u043e\u043a\u0435.<\/p>\n<pre><code class=\"javascript\">const minusScale = useSharedValue(1); const plusScale = useSharedValue(1);  \/\/ ... const minusAnimatedStyles = useAnimatedStyle(() => ({     transform: [{scale: minusScale.value }] })); const plusAnimatedStyles = useAnimatedStyle(() => ({     transform: [{scale: plusScale.value }] }));  const tap = Gesture.Pan().onUpdate(e => {     \/\/ .....     if (value === 0 &amp;&amp; e.translationX > -25  &amp;&amp; e.translationX &lt; 0) {         offset.value = e.translationX     } }).onEnd((e) => {     \/\/ ...      if (e.translationX > 30) {         plusScale.value = withSequence(withSpring(1.2), withSpring(1))         \/\/ ...     }     if (e.translationX &lt; -30 &amp;&amp; value > 0) {         minusScale.value = withSequence(withSpring(1.2), withSpring(1))         \/\/ ...     }     if (e.translationX &lt; 0 &amp;&amp; value === 0) {         minusScale.value = withSequence(withSpring(1.2), withSpring(1))     } })  \/\/ ...  &lt;Animated.View style={[styles.leftContainer, minusAnimatedStyles]}>     &lt;Text style={[styles.minusText, ...value &lt;= 0 ? [styles.disabledText] : [] ]}>-&lt;\/Text> &lt;\/Animated.View> \/\/ ... &lt;Animated.View style={[styles.rightContainer, plusAnimatedStyles]}>     &lt;Text style={styles.signText}>+&lt;\/Text> &lt;\/Animated.View> <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0437\u043d\u0430\u0447\u043a\u043e\u0432 \u043f\u043b\u044e\u0441 \u0438 \u043c\u0438\u043d\u0443\u0441 \u0442\u0430\u043a \u0436\u0435 \u0437\u0430\u0432\u0435\u0434\u0435\u043c 2 <code>shared values<\/code> \u0438 \u0445\u0443\u043a\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u044d\u0442\u0438\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438. \u0418\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u00a0\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u00a0\u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0436\u0435\u0441\u0442\u0430 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>withSequence<\/code> \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435\u00a0\u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432, \u0430\u00a0\u043f\u043e\u0442\u043e\u043c \u0432\u0435\u0440\u043d\u0443\u0432 \u043c\u0430\u0441\u0448\u0442\u0430\u0431.<\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0432 \u043f\u0440\u0438\u043b\u043e\u0435\u0436\u043d\u0438\u0438:<\/p>\n<pre><code class=\"javascript\">import 'react-native-gesture-handler' import {StyleSheet} from 'react-native'; import {StatusBar} from 'expo-status-bar'; import {GestureHandlerRootView} from 'react-native-gesture-handler' import Counter from \".\/src\/Component\";  export default function App() {     return (       &lt;GestureHandlerRootView style={styles.container}>           &lt;StatusBar style=\"auto\"\/>           &lt;Counter initValue={0} \/>       &lt;\/GestureHandlerRootView>     ); }  const styles = StyleSheet.create({     container: {         flex: 1,         backgroundColor: '#5a56fd',         alignItems: 'center',         justifyContent: 'center',     }, });<\/code><\/pre>\n<p>\u0418 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0443:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/63cc4d63a9cdfde0422821c1\" data-style=\"\" id=\"63cc4d63a9cdfde0422821c1\" width=\"\"><\/div>\n<p>\u0412\u0438\u0434\u043d\u043e, \u0447\u0442\u043e\u00a0\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 JS \u0438\u043b\u0438 UI \u043f\u043e\u0442\u043e\u043a\u0438 \u0438 \u044d\u0442\u043e \u043e\u0434\u043d\u043e \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 Reanimated.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043b\u0438\u0448\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0432\u0430\u0441 \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0430, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u043d\u0430 \u044e\u0442\u0443\u0431 \u043a\u0430\u043d\u0430\u043b\u0430\u0445: <a href=\"https:\/\/www.youtube.com\/@CatalinMironDev\/videos\" rel=\"noopener noreferrer nofollow\">Catalin Miron<\/a>, <a href=\"https:\/\/www.youtube.com\/@Reactiive\" rel=\"noopener noreferrer nofollow\">Reactiive<\/a> \u0438 <a href=\"https:\/\/www.youtube.com\/user\/wcandill\" rel=\"noopener noreferrer nofollow\">William Candillon<\/a>. \u041f\u0440\u0430\u0432\u0434\u0430 William Candillon \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043b\u0441\u044f \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 <a href=\"https:\/\/habr.com\/ru\/post\/685524\/\" rel=\"noopener noreferrer nofollow\">React Native Skia<\/a> \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u043f\u0438\u0441\u0430\u043b \u0432 <a href=\"https:\/\/habr.com\/ru\/post\/685524\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/711224\/\"> https:\/\/habr.com\/ru\/post\/711224\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>React Native \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 Animated API \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0447\u0430\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u043b\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0438\u00a0\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438\u00a0\u043d\u0430 60 fps, \u0431\u0435\u0437 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e Reanimated 2 \u0438 \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441\u0447\u0435\u0442\u0447\u0438\u043a\u0430.<\/p>\n<figure class=\"full-width\"><figcaption>\u0418\u0434\u0435\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 https:\/\/dribbble.com\/shots\/3368130-Stepper-Touch<\/figcaption><\/figure>\n<h2>Reanimated<\/h2>\n<p>\u0417\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438\u00a0\u0432 React Native \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 <a href=\"https:\/\/reactnative.dev\/docs\/animated\" rel=\"noopener noreferrer nofollow\">Animated API<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432. \u041e\u0434\u043d\u0430\u043a\u043e \u0443 \u043d\u0435\u0433\u043e \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 &#8212; \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 JS \u043f\u043e\u0442\u043e\u043a\u0435 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u044c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u0430 \u043d\u0430 UI \u043f\u043e\u0442\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>useNativeDriver<\/code><\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u043e\u0431\u0445\u043e\u0434\u0430 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u044b Software Mansion \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/docs.swmansion.com\/react-native-reanimated\/\" rel=\"noopener noreferrer nofollow\">Reanimated<\/a> \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435-\u0444\u0430\u043a\u0442\u043e \u0441\u0442\u0430\u043b\u0430 \u0441\u0430\u043c\u044b\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0432 React Native.\u00a0\u0427\u0442\u043e\u0431\u044b \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438\u0442\u044c JS \u043f\u043e\u0442\u043e\u043a \u043e\u0442 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 Reanimated \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 JS \u043f\u043e\u0442\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u042d\u0442\u043e \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0438 \u0432\u0432\u043e\u0434\u0438\u0442 2 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 <strong>Worklets<\/strong> \u0438 <strong>Shared Values<\/strong>.<\/p>\n<h2>Worklets<\/h2>\n<p>\u0412\u043e\u0440\u043a\u043b\u0435\u0442\u044b\u00a0\u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u0445 Reanimated \u044d\u0442\u043e\u00a0\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435\u00a0JS \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f\u00a0\u0432\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c JS \u043f\u043e\u0442\u043e\u043a\u0435 \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439.\u00a0\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e\u00a0\u043d\u0443\u0436\u043d\u043e \u0447\u0442\u043e\u0431\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0442\u0430\u043b\u0430\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u043c\u00a0\u044d\u0442\u043e \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u043e\u0439 <code>worklet<\/code><\/p>\n<pre><code class=\"javascript\">function someWorklet(greeting) {   'worklet';   console.log(\"Hey I'm running on the UI thread\"); }<\/code><\/pre>\n<p>\u0412\u043e\u0440\u043a\u043b\u0435\u0442\u044b \u0442\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c JS. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c JS \u043f\u043e\u0442\u043e\u043a\u0435. \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u043e\u0440\u043a\u043b\u0435\u0442. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0430.<\/p>\n<pre><code class=\"javascript\">const width = 135.5;  function otherWorklet(greeting) {   'worklet';   console.log(greeting, 'From the UI thread');   console.log('Captured width is', width); }<\/code><\/pre>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 React Native \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>runOnJS<\/code><\/p>\n<pre><code class=\"javascript\">function callback(text) {   console.log('Running on the RN thread', text); }  function someWorklet() {   'worklet';   console.log(\"I'm on UI but can call methods from the RN thread\");   runOnJS(callback)('can pass arguments too'); }<\/code><\/pre>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u044b \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0435 \u0447\u0430\u0441\u0442\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0445\u0443\u043a\u043e\u0432 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0432\u043e\u0440\u043a\u043b\u0435\u0442\u044b.<\/p>\n<h2>Shared values<\/h2>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043e\u0434\u043d\u0438\u0445 \u0442\u043e\u043b\u044c\u043a\u043e\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u0432\u00a0\u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0436\u043d\u043e\u0439 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f Shared values. \u041e\u043d\u0438 \u0440\u0435\u0448\u0430\u044e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c,\u00a0\u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445\u00a0\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u00a0\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u00a0\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u043c\u044f\u0442\u0438 \u0434\u043b\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 JS \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u0412\u0442\u043e\u0440\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u044d\u0442\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c, Reanimated \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u0440\u0430\u0444 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043c\u0435\u0436\u0434\u0443 Shared values \u0438\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u0430\u043c\u0438\u00a0\u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f. \u0414\u0430\u043b\u0435\u0435 \u0435\u0441\u043b\u0438\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u00a0\u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u043b\u0438 \u043a\u043e\u0433\u0434\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f shared value \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0435 \u0441 \u044d\u0442\u0438\u043c\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u043e\u043c.<\/p>\n<pre><code class=\"javascript\">import Animated, {   useSharedValue,   useAnimatedStyle, } from 'react-native-reanimated';  function Box() {   const offset = useSharedValue(0);    const animatedStyles = useAnimatedStyle(() => {     return {       transform: [{ translateX: offset.value }],     };   });    return (     &lt;>       &lt;Animated.View style={[styles.box, animatedStyles]} \/>       &lt;Button onPress={() => (offset.value = Math.random() * 255)} title=\"Move\" \/>     &lt;\/>   ); }<\/code><\/pre>\n<p><code>useAnimatedStyle<\/code> \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u00a0\u0432\u043e\u0440\u043a\u043b\u0435\u0442\u00a0\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u043e\u0433\u0434\u0430 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f\u00a0\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00a0<code>offset.value<\/code> \u0441\u0442\u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u0422\u0440\u0435\u0442\u044c\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435 <code>View<\/code> \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e, \u043d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u044d\u0442\u043e \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 <code>shared values<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e time-based\u00a0\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439.\u00a0\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438\u00a0\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>withSpring<\/code><\/p>\n<pre><code class=\"javascript\">&lt;Button   onPress={() => {     offset.value = withSpring(Math.random() * 255);   }}   title=\"Move\" \/><\/code><\/pre>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Reanimated <\/h2>\n<p>\u0411\u0435\u0437 \u0443\u0447\u0435\u0442\u0430 \u0441\u0442\u0438\u043b\u0435\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0432 70 \u0441\u0442\u0440\u043e\u043a. \u041f\u043e\u0434 \u043a\u0430\u0442\u043e\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0435\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {useState} from 'react'; import {Gesture, GestureDetector} from 'react-native-gesture-handler' import MaskedView from '@react-native-masked-view\/masked-view'; import Animated, {     withSequence,     useAnimatedStyle,     useSharedValue,     withSpring,     runOnJS, } from 'react-native-reanimated'; import {StyleSheet, Text, View} from \"react-native\";  const Counter = ({initValue = 0}) => {     const [value, setValue] = useState(initValue)          const offset = useSharedValue(0);     const minusScale = useSharedValue(1);     const plusScale = useSharedValue(1);      const ballAnimatedStyles = useAnimatedStyle(() => ({         transform: [{translateX: offset.value }]     }));     const minusAnimatedStyles = useAnimatedStyle(() => ({         transform: [{scale: minusScale.value }]     }));     const plusAnimatedStyles = useAnimatedStyle(() => ({         transform: [{scale: plusScale.value }]     }));      const tap = Gesture.Pan().onUpdate(e => {         if (e.translationX > 0 &amp;&amp; e.translationX &lt; 75) {             offset.value = e.translationX         } else if (value > 0 &amp;&amp; e.translationX > -75  &amp;&amp; e.translationX &lt; 0) {             offset.value = e.translationX         } else if (value === 0 &amp;&amp; e.translationX > -25  &amp;&amp; e.translationX &lt; 0) {             offset.value = e.translationX         }     }).onEnd((e) => {         offset.value = withSpring(0)          if (e.translationX > 30) {             plusScale.value = withSequence(withSpring(1.2), withSpring(1))             runOnJS(setValue)(value + 1)         }         if (e.translationX &lt; -30 &amp;&amp; value > 0) {             minusScale.value = withSequence(withSpring(1.2), withSpring(1))             runOnJS(setValue)(value - 1)         }         if (e.translationX &lt; 0 &amp;&amp; value === 0) {             minusScale.value = withSequence(withSpring(1.2), withSpring(1))         }     })      return &lt;MaskedView       style={styles.maskContainer}       androidRenderingMode=\"software\"       maskElement={&lt;View style={styles.maskElementContainer} \/>}     >         &lt;View style={[styles.controlContainer]}>             &lt;Animated.View style={[styles.leftContainer, minusAnimatedStyles]}>                 &lt;Text style={[styles.minusText, ...value &lt;= 0 ? [styles.disabledText] : [] ]}>-&lt;\/Text>             &lt;\/Animated.View>             &lt;GestureDetector gesture={tap}>                 &lt;Animated.View style={[styles.ballContainer, ballAnimatedStyles]}>                     &lt;Text style={styles.counterText}>{value}&lt;\/Text>                 &lt;\/Animated.View>             &lt;\/GestureDetector>             &lt;Animated.View style={[styles.rightContainer, plusAnimatedStyles]}>                 &lt;Text style={styles.signText}>+&lt;\/Text>             &lt;\/Animated.View>         &lt;\/View>     &lt;\/MaskedView> }  const styles = StyleSheet.create({     maskContainer: {         width: 180,         height: 80,     },     maskElementContainer: {         width: 180,         height: 80,         borderRadius: 40,         backgroundColor: '#7775ff',         zIndex: 0     },     controlContainer: {         flexDirection: 'row',         alignItems: 'center',         justifyContent: 'space-between',         width: 180,         height: 80,         borderRadius: 40,         backgroundColor: '#7775ff',     },     ballContainer: {         alignItems: 'center',         justifyContent: 'center',         width: 80,         height: 80,         borderRadius: 40,         backgroundColor: '#fff',         zIndex: 20     },     signText: {         fontSize: 36,         color: '#fff',         fontFamily: 'monospace',     },     minusText: {         fontSize: 36,         color: '#fff',         fontFamily: 'monospace',     },     disabledText: {         color: 'rgba(256, 256, 256, 0.4)',     },     leftContainer: {         flex: 1,         alignItems: 'center',     },     rightContainer: {         flex: 1,         alignItems: 'center',     },     counterText: {         fontSize: 36,         color: '#7775ff',         fontFamily: 'monospace',         fontWeight: 'bold'     }, });  export default Counter <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e Reanimated \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f <a href=\"https:\/\/docs.swmansion.com\/react-native-gesture-handler\/\" rel=\"noopener noreferrer nofollow\">Gesture Handler<\/a> \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0430\u0441\u043a\u0438 <a href=\"https:\/\/github.com\/react-native-masked-view\/masked-view\" rel=\"noopener noreferrer nofollow\">Masked View<\/a>.<\/p>\n<pre><code class=\"javascript\">&lt;MaskedView       style={styles.maskContainer}       androidRenderingMode=\"software\"       maskElement={&lt;View style={styles.maskElementContainer} \/>}     >         &lt;View style={[styles.controlContainer]}>             &lt;Animated.View style={[styles.leftContainer, minusAnimatedStyles]}>                 &lt;Text style={[styles.minusText, ...value &lt;= 0 ? [styles.disabledText] : [] ]}>-&lt;\/Text>             &lt;\/Animated.View>             &lt;GestureDetector gesture={tap}>                 &lt;Animated.View style={[styles.ballContainer, ballAnimatedStyles]}>                     &lt;Text style={styles.counterText}>{value}&lt;\/Text>                 &lt;\/Animated.View>             &lt;\/GestureDetector>             &lt;Animated.View style={[styles.rightContainer, plusAnimatedStyles]}>                 &lt;Text style={styles.signText}>+&lt;\/Text>             &lt;\/Animated.View>         &lt;\/View> &lt;\/MaskedView><\/code><\/pre>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 <code>MaskedView<\/code> \u0438 \u0442\u0440\u0435\u0445 <code>Animated.View<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c &#8212; \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u043a\u0438 \u043f\u043b\u044e\u0441\u0430 \u0438 \u043c\u0438\u043d\u0443\u0441\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0438. \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0436\u0435\u0441\u0442\u0430 \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>GestureDetector<\/code>.<\/p>\n<pre><code class=\"javascript\">\/\/ ... const offset = useSharedValue(0);  const ballAnimatedStyles = useAnimatedStyle(() => ({   transform: [{translateX: offset.value }] })); \/\/ ... const tap = Gesture.Pan().onUpdate(e => {     if (e.translationX > 0 &amp;&amp; e.translationX &lt; 75) {         offset.value = e.translationX     } else if (value > 0 &amp;&amp; e.translationX > -75  &amp;&amp; e.translationX &lt; 0) {         offset.value = e.translationX     } }).onEnd((e) => {     offset.value = withSpring(0)      if (e.translationX > 30) {         runOnJS(setValue)(value + 1)     }     if (e.translationX &lt; -30 &amp;&amp; value > 0) {         runOnJS(setValue)(value - 1)     } }) \/\/ ... &lt;GestureDetector gesture={tap}>   &lt;Animated.View style={[styles.ballContainer,<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-344297","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/344297","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=344297"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/344297\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=344297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=344297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=344297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}