<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Jiří Otáhal]]></title><description><![CDATA[Jiří Otáhal]]></description><link>https://blog.xotahal.cz/</link><image><url>https://blog.xotahal.cz/favicon.png</url><title>Jiří Otáhal</title><link>https://blog.xotahal.cz/</link></image><generator>Ghost 3.31</generator><lastBuildDate>Sun, 05 Apr 2026 04:18:23 GMT</lastBuildDate><atom:link href="https://blog.xotahal.cz/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Semantic Release for Fastlane]]></title><description><![CDATA[Versioning and release notes. Fully automated.]]></description><link>https://blog.xotahal.cz/semantic-release-for-fastlane/</link><guid isPermaLink="false">5ca44fd29cffe006e8d5305b</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Wed, 03 Apr 2019 06:30:17 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2019/04/Main.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2019/04/Main.png" alt="Semantic Release for Fastlane"><p><strong><strong>Boss:</strong></strong> “Can you release a new version of <code>Android Alpha</code>?”<br><strong><strong>Developer:</strong></strong> “ Yeah, sure. Hmm 🤔. Hey boss, how should I do that?”<br><strong><strong>Boss: </strong></strong>“Just run <code>fastlane android alpha</code>.”<br><strong><strong>Developer:</strong></strong> “Yeah, but what about version? Shouldn’t I update it in those Gradle files?”<br><strong><strong>Boss:</strong></strong> “No. Just run <code>fastlane android alpha</code>.”<br><strong><strong>Developer:</strong></strong> “And build number? We use it as a version code on google play.”<br><strong><strong>Boss: </strong></strong>“Just run <code>fastlane android alpha</code> and let’s have a coffee. ☕ I’ll tell you how it works.”</p><figure class="kg-card kg-image-card kg-width-full"><img src="https://cdn-images-1.medium.com/max/2560/1*NaBTN1eXi3KC2IO6ncgX7Q.png" class="kg-image" alt="Semantic Release for Fastlane"></figure><p>Recently I was thinking about how to use <a href="https://github.com/semantic-release/semantic-release" rel="noopener">semantic release</a> package for my React Native Apps that use Fastlane. I like the idea to absolutely not think about versioning or build numbers. And I like <a href="https://www.conventionalcommits.org/en/v1.0.0-beta.3/" rel="noopener">conventional commits</a>.</p><h2 id="semantic-release-as-a-fastlane-plugin-">Semantic release as a Fastlane plugin 🎉</h2><p>That’s why I wrote this plugin. When you install the <code>semantic_release</code> plugin to your Fastlane. You’ll be able to use these actions — <code>analyze_commits</code> and <code>conventional_changelog</code>. The code is open-sourced on <a href="https://github.com/xotahal/fastlane-plugin-semantic_release" rel="noopener">my GitHub</a>. This plugin is also used for releasing the plugin itself. So you can get inspired in the Fastfile!fastlane add_plugin semantic_release</p><h2 id="fastlane-config-of-react-native-app">Fastlane Config of React Native App</h2><p>I will share with you a simplified config of my Fastlane. First of all, we need to find out what build number is next. Because we use build number as a version code on google play. This happens before all lanes. (Read comments in the snippet.)</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/b424ad51b25125c8f7223ff0c10f9566.js"></script><!--kg-card-end: html--><h2 id="ios-alpha-deploy">iOS Alpha Deploy</h2><p>Let’s go step by step from the end of the workflow.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/0cfa791bebf48b841f53d30a6058991f.js"></script><!--kg-card-end: html--><h4 id="post-deploy">Post Deploy</h4><ul><li>generates a changelog</li><li>pushes a tag of the next version to the GIT repository</li><li>sends release notes to the Slack channel</li></ul><p>A format of the tag is always <code>[platform]/[flavor]/[semver]/[build_number]</code>. It uses this tag to know what version was deployed last time. You might be wondering where we got the <code>next_version</code>. It is generated by <code>analyze_commits</code> action. We’ll talk about it later. Now, let’s talk about <code>conventional_changelog</code> action.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/c6b851d28aefa4817d999ab4ea45a95f.js"></script><!--kg-card-end: html--><h4 id="conventional-changelog-action">Conventional Changelog Action</h4><p>What do you get when you use <code>conventional_changelog</code>? Look at the right side of the following picture. That’s what you get as a <code>string</code>. The changelog grouped by types of commits.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cdn-images-1.medium.com/max/1200/1*YxZAKfIAwMX2B18fKBMoJg.png" class="kg-image" alt="Semantic Release for Fastlane"></figure><p>It takes commits marked as a <code>fix</code> and commits marked as a <code>feat</code>, groups them and create this changelog in either <code>slack</code> or <code>markdown</code> format. You can set up section titles and also their order. You can set up which commits will be skipped and which will be included in the changelog. Everything is up to you!</p><h4 id="build">Build</h4><p>In this step, we need to take the <code>next_version</code> number and save it to Xcode files. We use already known Fastlane actions as <code>increment_version_number</code> or <code>increment_build_number_in_plist</code>. Easy with Fastlane!</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/304647df70b6836810b399308ee546a4.js"></script><!--kg-card-end: html--><h4 id="build-android">Build — Android</h4><p>Just short jump to the build of Android workflow. Maybe you are wondering how to set up the version in <code>app/build.gradle</code> file. We send properties to the Gradle task. Build number and next version.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/169e7774a27cc26036bd10ba32a30663.js"></script><!--kg-card-end: html--><p>Later in <code>build.gradle</code> I get these properties and set the default config for <code>versionCode</code> and <code>versionName</code>.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/489d1337273f8fb85797a0e181d09ead.js"></script><!--kg-card-end: html--><h4 id="verify">Verify</h4><p>Back to iOS. That’s the action where everything starts. First of all, it ensures that GIT status is clean. Then we split run to “On CI Machine” and “On Local Machine”. Just because we want to save some minutes on CircleCI. We usually deploy both <code>iOS</code> and <code>Android</code> versions together. So we don’t have to install dependencies and check the code quality twice.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/84d54fe3ad6ac9fadafb55540cd2b77e.js"></script><!--kg-card-end: html--><h4 id="analyze-commits-action">Analyze Commits Action</h4><p>Returns <code>true</code> if the version should be released. It also provides some useful variables to the <code>lane_context</code>. So you have access to them everywhere in Fastlane. For example, the execution on the following picture would store <code>1.4.2</code> to the <code>lane_context[SharedValues::RELEASE_NEXT_VERSION]</code>. We used it before in those snippets. 😉</p><p>This action is very useful when you have set up nightly deploys with CI. If there are no changes since the last night it won’t be deployed. Or if there are only changes that do not have any impact on the app itself. For example, just updating documentation or building scripts.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://cdn-images-1.medium.com/max/1200/1*Bp4n9HenMWlB6tkWYSdFOg.png" class="kg-image" alt="Semantic Release for Fastlane"></figure><h2 id="how-do-you-release-your-react-native-app">How do you release your React Native app?</h2><p>Please let me know what do you think about this plugin. Would it be helpful for you? Do you need to adjust some parameters of the actions? Do you need to add some action to make your release absolutely automated?</p>]]></content:encoded></item><item><title><![CDATA[React Native Continuous Deployment]]></title><description><![CDATA[Release only when there is change. Increment version number. Generate release notes. Everything automatically!]]></description><link>https://blog.xotahal.cz/react-native-continuous-deployment/</link><guid isPermaLink="false">5c7c613499cd012470cebe85</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Thu, 07 Mar 2019 22:54:42 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2019/03/Main-Picture-4.png" medium="image"/><content:encoded><![CDATA[<blockquote><em>Is it deployable? What is the next version number? How to generate release notes automatically?</em></blockquote><img src="https://blog.xotahal.cz/content/images/2019/03/Main-Picture-4.png" alt="React Native Continuous Deployment"><p>Alpha. Beta. Production. Times two — iOS and Android. Plus Codepush. Those could be versions of your React Native app. I want to share with you guys how we deploy everything automatically by using GIT flow and <a href="https://www.conventionalcommits.org/en/v1.0.0-beta.3/" rel="noopener">Conventional Commits</a>. Inspired by <a href="https://github.com/semantic-release/semantic-release" rel="noopener">semantic-release</a>.</p><figure class="kg-card kg-image-card kg-width-full"><img src="https://blog.xotahal.cz/content/images/2019/03/Main-Picture.png" class="kg-image" alt="React Native Continuous Deployment"></figure><h2 id="when-do-we-release-those-versions">When do we release those versions?</h2><ul><li><strong><strong>Alpha Version</strong></strong>. Every night. For in-house testing. Based on the develop branch.</li><li><strong><strong>Beta Version</strong></strong>. Triggered by pushing to the beta branch.</li><li><strong><strong>Production Version</strong></strong>. Uploaded to Apple Store and Google Play. Triggered by pushing to master branch.</li></ul><p>All those versions are released only when there is <strong><strong>a reason</strong></strong> to release it. If there is no new commit since the last version the workflow will be canceled <strong><strong>automatically</strong></strong>.</p><h2 id="how-does-our-version-look-like">How does our version look like?</h2><p>We use a <a href="https://semver.org/" rel="noopener">semver</a>. Major. Minor. Patch. It could be <code>1.3.4</code>. When we release a version, we create a unique tag in the GIT. For example, <code>android/production/1.3.4/7683</code> or <code>ios/alpha/1.5.0/8754</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*gnCFcpeueGz3BzZ1vbN-zA.png" class="kg-image" alt="React Native Continuous Deployment"><figcaption>Our tag system — [platform]/[flavor]/[version]/[build number]</figcaption></figure><h4 id="why-we-do-not-store-version-in-a-package-json-">Why we do not store version in a package.json 🚫</h4><p>If we stored the version in<code>package.json</code> file (as many people do) we wouldn’t be able to increase the version automatically. Because it is changed by CircleCI and CircleCI would have to push the change back to the repository. That would trigger a new release. Because every single push triggers a release. Not talking about how many <code>Bump version</code> commits we would have in the history of GIT.</p><h2 id="how-does-it-work-with-production-release">How does it work with Production Release?</h2><p>In this example, we push to the master branch and expect Android and the iOS app will be uploaded to the stores. We will simulate a fail of the iOS build.</p><h3 id="push-to-master-1">Push to Master #1</h3><p>The master branch was “fast forwarded” (merged) from the commit <code>A</code> to the commit <code>D</code>. The last version for both is on commit <code>A</code> (see tags).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*38WCelH7asqgdyHCsDJ4Jg.png" class="kg-image" alt="React Native Continuous Deployment"><figcaption>Git History After Merge Master&nbsp;Branch</figcaption></figure><p>Release workflow is triggered. First step. Install dependencies. No big deal. It only creates a node modules folder. The second step. Code quality check. Jest. Lint. Flow. If one of them ends up with an error, the whole workflow will be canceled.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/1200/1*Ou1dCUR81x2sCu4t8LWt7Q.png" class="kg-image" alt="React Native Continuous Deployment"><figcaption>Production Release&nbsp;Workflow</figcaption></figure><p>After this step, our workflow is separated into the Android branch and iOS branch. And this is a point where the commit analysis plays a big part in the workflow.</p><p><strong><strong>Android</strong></strong><br>Our script (Android Analysis) finds the last tag for <code>android/production</code>(simply by using the git command line tool). The tag is found on the commit <code>A</code>. It gets the last version by parsing of the tag name. It is <code>1.3.4</code>. Then, by analyzing commits, it finds out a next version number.</p><ul><li>Commit <code>B</code>. Feature (<code>feat</code> keyword). It means we have to increase a minor number <code>1.4.0</code>. If you increase the minor number you must reset patch number (see <a href="https://semver.org/" rel="noopener">semver</a> documentation).</li><li>Commit <code>C</code>. Fix (<code>fix</code> keyword). Increases patch number <code>1.4.1</code>.</li><li>Commit <code>D</code>. It is just an update of documentation (<code>doc</code> keyword). There is no change in the version number.</li></ul><p>That’s it. We got the next version number. No manual actions! Next version <code>1.4.1</code> is higher than the current version <code>1.3.4</code>. Release continues. Decided automatically. We can pass the number to the Fastlane and build a release. Once the build is ready, it continues by deploying the version to the store. After deployment, it creates a new tag on <code>HEAD</code> (commit <code>D</code>) and generates release notes. Android is done!</p><p><strong><strong>iOS</strong></strong><br>Our script (iOS Analysis step) finds the last tag for <code>ios/production</code>. It continues in the same way as the android part. It gets the next version number <code>1.4.1</code> and continues to build and deploy steps.</p><p>To make it a bit complicated, let’s say that the build of the iOS release failed. Because of our build tool is badly configurated.</p><p>What should we do now? Android is already released. If we change something and push to the master it will release Android again. We could wait on CircleCI and cancel the job manually. 🤔 Fortunately, we don’t have to. Let’s see why.</p><h3 id="push-to-master-2">Push to master #2</h3><p>We fixed the problem that caused our iOS app wasn’t released. Now we pushed the fix to the master. It will trigger the deployment workflow again. But because of our scripts, the workflow will be different this time.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*pzRfMTsSrOsYA9Qoed7_1w.png" class="kg-image" alt="React Native Continuous Deployment"></figure><p><strong><strong>Android</strong></strong><br>There is only one commit since the last version of android production (<code>1.4.1</code>). And that’s what was changed since the last release. Because Android was successfully released (Push to master #1). The new commit <code>E</code> won’t increase a version number. Because it is just updating of building tools. The workflow for Android ends with Android Analysis step.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/1200/1*fxmmFu4_96jRC65N0yF-nA.png" class="kg-image" alt="React Native Continuous Deployment"><figcaption>Production Release&nbsp;Workflow</figcaption></figure><p><strong><strong>iOS</strong></strong><br>The situation will be the same as during the push to master #1. There is only one commit more. But this commit doesn’t change the version. The last release of the iOS version is <code>1.3.4</code> on commit <code>A</code>. It analyses commits and finds out that the new version will be <code>1.4.1</code>. It continues with the build, deploy and it will be successful this time. 🎉</p><p>Even though we pushed to the master again, the Android version wasn’t released again. We didn’t have to cancel anything manually. Everything works automatically. Just by analyzing commits.</p><h2 id="release-notes">Release Notes</h2><p>It can even generate release notes by analyzing of the commits. This is our GIT history after the push to master #2.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*t0FwBH6OMrjt-VSj2_H6aw.png" class="kg-image" alt="React Native Continuous Deployment"><figcaption>GIT History after Push to Master&nbsp;#2</figcaption></figure><p>Release notes for iOS include commit <code>B</code> as a new feature and commit<code>C</code> as a fix (patch). It will skip commit <code>C</code> and commit <code>D</code> because they don’t change anything for users.</p><h2 id="codepush-friendly-">Codepush friendly? 👍</h2><p>You very likely already heard about codepush. A tool that provides us a possibility to release only javascript part. Users would get updates immediately. Nice idea. But in the real world, when we were preparing a release, it was always hard to know if we can release just a javascript or not. There were always doubts. And something extra we needed to do every release.Now, we have this release tool. It analyzes commits for us. Our developers just have to mark the commit they are working on. Let’s say they will write a keyword to the commit message. For example <code>[codepush-ok]</code>.Then it does exactly the same as during the upload to the stores. Finds the last tag of codepush release. Analyze commits since that release. If there is one commit which is not marked as <code>[codepush-ok]</code> it will cancel deploy. If all commits are marked with <code>[codepush-ok]</code> we can release codepush version. Isn’t it easy?</p><h2 id="how-do-you-release-react-native-apps">How do you release React Native apps?</h2><p>I’ll be happy if you leave a comment and tell me your secret about releasing. How do you deal with versioning of React Native app? Are you still doing that manually? Do you use <code>package.json</code>?</p>]]></content:encoded></item><item><title><![CDATA[Animated Graph in React Native]]></title><description><![CDATA[You will learn how to build an animated graph in React Native by only Animated API and Views.]]></description><link>https://blog.xotahal.cz/animated-graph-in-react-native/</link><guid isPermaLink="false">5bb02320d9a4290c97a5accc</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Fri, 22 Jun 2018 02:21:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/stock-photo-88668013.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2018/09/stock-photo-88668013.jpg" alt="Animated Graph in React Native"><p>Recently I was looking for a React Native graph library for my <a href="http://savee.io">Savee.io</a> app. During the research, I realized it’s not easy to deal with graphs in React Native. And if you want to animate them? It looks almost impossible. The following gif is what I have done and will talk about in this tutorial!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*_Mzui8ijFb5GaD4oyyI2Mw.gif" class="kg-image" alt="Animated Graph in React Native"><figcaption>Goal of this&nbsp;article</figcaption></figure><h3 id="without-art-library">Without ART library</h3><p>When I was doing my research about charts in React Native, I found out that almost everyone uses the ART library. Which is really cool and powerful drawing library. Look at this <a href="https://medium.com/how-i-built-profitable-application-faster-than/day-76th-a6e0497794f2">pie chart</a> that has been done by ART library for the <a href="https://savee.io">Savee.io</a> app.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*wXTdAET4Rx6C_3hvwINr8A.png" class="kg-image" alt="Animated Graph in React Native"><figcaption>ART library Pie Chart in&nbsp;savee.io</figcaption></figure><p>But when you want to animate it? Well, you can. It is possible. But the animation is done by JS thread. I am always trying to find a way how to move everything to a native part, so our JS thread is not blocked by animation and can work on something else.</p><p>The column chart I am going to talk about (and you can see in the gif below) has been done by pure React Native. <strong><strong>No ART library!</strong></strong></p><h2 id="let-s-make-it-a-bit-complicated">Let’s make it a bit complicated</h2><p>I realized that I also need a negative value in the graph. Users of Savee.io usually create a group for a trip and track their spendings. Obviously, there are only negative values — only spendings. The following gif shows how the animation looks like for both negative and positive values.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*PiQ9otRXmAwBmiY0BH6Pww.gif" class="kg-image" alt="Animated Graph in React Native"></figure><h3 id="layout">Layout</h3><p>I decided to make every single column separately as a component. So I could add a “delay” effect. You can see that the animation starts randomly for every single column when the graph is changing a position of baseline. Let’s work with the 200 height. Value’s height could be 25 and label’s height 25 as well. That makes 150 for column.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*jG38Lwqkh4R-f80GbZgq5g.png" class="kg-image" alt="Animated Graph in React Native"><figcaption>Layout for a single&nbsp;column</figcaption></figure><p>If the graph’s height is 150 then the column’s height is 300. Every column has a positive part (A) and a negative part (B). Opposite side of these parts is always hidden. The A is hidden for the negative part and the B is hidden for the positive part. It means that if we move the positive part (A) underneath of baseline to the B space, the positive column will be completely hidden. That’s what we want when the value is negative.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/600/1*0Lq-GgyOGvBWC72peB0B6g.png" class="kg-image" alt="Animated Graph in React Native"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/600/1*K-B3j-rXk26G8p1JsSroWg.png" class="kg-image" alt="Animated Graph in React Native"><figcaption>Positive parts of columns (left side) and negative parts of the same columns (right&nbsp;parts)</figcaption></figure><p>You can see the negative value for the last column on the picture. The value is -5. Positive column is completely moved underneath of baseline (it’s hidden) and negative column is moved to proper Y position to represent -5 value. A maximum value for this graph is 10 (first column). It means that the -5 will be in the middle of a negative part (75 / 2).</p><p>We need to do a bit of math here because we need to interpolate actual value to Y position. But I am not going to talk about this here. I believe that you can figure everything out pretty easily.</p><h2 id="animated-column">Animated Column</h2><p>I used my open source library called <a href="http://bit.ly/react-native-motion" rel="nofollow noopener">react-native-motion</a> and component TranslateY. Which makes animations really easy to implement. Look at the code. Easy to understand. We use TranslateY component in the same way as we would use View component. The only thing we need to do is compute Y positions for positive column, negative column, baseline, and a value label.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/6df4809cfbd6ffd8a5d7ae6773656c00.js"></script><!--kg-card-end: html--><p>Check out the result in a real application. <a href="https://savee.io">Savee.io</a> already implemented the column chart. As I said before, everything is done by UI thread (it’s pretty fast). There is an onPress event so you can change the months. When you select the category it will change the values of a graph and recomputes Y positions. Then the react-native-motion takes care of animation.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/400/1*EsxHNM0Rss7E9cpInkSuTA.gif" class="kg-image" alt="Animated Graph in React Native"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/400/1*XcL2BPEnjdWr8aESa9_52A.gif" class="kg-image" alt="Animated Graph in React Native"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/400/1*NfeY51kMCRgp57KnmbOUiw.gif" class="kg-image" alt="Animated Graph in React Native"></figure><h2 id="animated-number">Animated Number</h2><p>The number animation is a bit problem. Because we can’t move it to UI thread. It has to be done by JS thread. I’ve seen that developers usually have the effect done by setInterval. Of course, you can use it, but I wanted to do it safer.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*_Mzui8ijFb5GaD4oyyI2Mw.gif" class="kg-image" alt="Animated Graph in React Native"></figure><p>So I use React Native’s Animated API even for the number animation. We can add a listener to animated value and when the value is changed we just re-render the number. It’s easy and you can take advantage of the Animated API. By using an Easing for example. And what’s the best? I put the component to the <strong><strong>react-native-motion </strong></strong>library which is open-sourced for you guys 😉</p><p>You just have to write a couple of lines like this. Once the value is changed in your code it will take care of the rest.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*CTMFVLB6HDd4yMLor9iZhw.png" class="kg-image" alt="Animated Graph in React Native"><figcaption>Available in <strong class="markup--strong markup--figure-strong" style="font-weight: 700;">react-native-motion</strong></figcaption></figure><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h3 id="did-you-like-it-clap-comment-share-and-follow-me-"><strong><strong><strong>Did you like it? Clap, Comment, Share and Follow me! 👏</strong></strong></strong></h3><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-"><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>About me 👦</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></h3><p>I am an author of <a href="https://savee.io/">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz/">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a><br>📚 <em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em><br>🚧 <em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></p>]]></content:encoded></item><item><title><![CDATA[Animated Login Flow in React Native]]></title><description><![CDATA[You will learn how to create a smooth signup/login flow for your React Native app]]></description><link>https://blog.xotahal.cz/animated-login-flow-in-react-native/</link><guid isPermaLink="false">5bb01e5fd9a4290c97a5acc8</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Thu, 17 May 2018 01:52:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/stock-photo-128675389.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2018/09/stock-photo-128675389.jpg" alt="Animated Login Flow in React Native"><p>Today’s goal is the login/logout flow which you can see on the gif!</p><figure class="kg-card kg-image-card"><img src="https://blog.xotahal.cz/content/images/2018/09/login-flow-final-1.gif" class="kg-image" alt="Animated Login Flow in React Native"></figure><p>When I was building an application it was always hard to deal with login flow. From the navigation point of view, from a user point of view, from the clean code point of view.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*a8NwVLJG5LgDSXj_cyl7Dg.png" class="kg-image" alt="Animated Login Flow in React Native"></figure><p>If the user previously signed up to the app it should try to log in automatically (1). So the user doesn’t have to do anything. If it is a new user the application should render login/signup form (2). So the user can create an account. Then we usually want to get some data (3). Prepare the app to use. And finally, we can render the app itself (authorized part of the app).</p><h2 id="use-navigation">Use navigation</h2><p>I usually use react-navigation as a navigation library. For me, every single step is separated from each other and written as a page/screen. So if I have a bigger onboard flow I can add or remove the step very easily. Below, you can see the code of login flow controller (guys call it Switch in react-navigation). It is very simple approach how to render particular page when the redux state was changed. This controller is always mounted. So if we want to logout user, we can just set <code>loggedUser</code> variable to <code>null</code> in redux store and this controller will render <code>LoginScreen</code>. Easy and clean!</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/1000/1*hayZZYcUEaRuaDgDkhjTwA.png" class="kg-image" alt="Animated Login Flow in React Native"></figure><p>So at this stage, we have a clean code and clean navigation. But the user will see just flickering screens (like on the gif below). We actually don’t know how long those screens will be visible. It can be only 100ms. So every 100ms React renders a new screen. The user could be confused here. I wanted to do it smoothly and understandable. I decided to cover all those screens by only one screen with the logo of application.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/1000/1*fJvPczqjs85vQqhSawI2EQ.gif" class="kg-image" alt="Animated Login Flow in React Native"><figcaption>Flickering login&nbsp;flow</figcaption></figure><h2 id="how-is-it-done">How is it done?</h2><p>It is so simple that there is no need to show the code. There is a redux store variable which represents the Y position of the cover screen. If the variable is set to zero the component completely covers the application and if the variable is set to - <code>window.height</code> the component is out of the screen — so the user can see the application. Easy, right?</p><p>Note that we are using <code>useNativeDriver</code><em> </em>so the animation won’t block JS thread!</p><h2 id="logout-animation">Logout Animation</h2><p>There could be someone who is confused by logout animation. Because I said that the cover screen is completely out of the mobile’s viewable area. So if we animated the cover screen from there it would look like on the picture below.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/1000/1*lVlVTlsXo4yo33FstPvUKw.png" class="kg-image" alt="Animated Login Flow in React Native"></figure><p>The header would be covered by the cover screen during the animation (right part of the picture). Which is not what we want to do. So before the animation itself, we render exactly the same header on a bottom of the cover screen. Then we have to find out where the header’s bottom position is (status bar height<em> + </em>height of header). Once we know the position, we can use <code>setValue</code><em> </em>on <code>AnimatedValue</code> and set the position of the cover screen immediately (without animation — right part of the picture below). After this, we can animate the cover screen down as usual.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/1000/1*HDqabe9A_KEPmL85Rc-7xQ.png" class="kg-image" alt="Animated Login Flow in React Native"></figure><h2 id="logout-is-in-progress">Logout is in progress</h2><p>The last animation we are going to talk about is how to clarify the progress of logout process. I decided to use this animation because it looks like it is actually forgetting the user (he is disappearing).</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/1000/1*OrWV-XAZDJ0z41KwUNvSVg.gif" class="kg-image" alt="Animated Login Flow in React Native"></figure><p>It is simple opacity animation with some rotation on the right settings icon. The most interesting is the text. Someone could think it is done by setTimeout or by something similar. By it’s not. We actually listen to the progress of opacity value. For example, if the opacity is in the middle (value 0.5) the code will looks like this.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*qBH-kjdp7Fzb-M7LCXnSiQ.png" class="kg-image" alt="Animated Login Flow in React Native"></figure><p>It is a good approach how to do that because we can use all advantages of Animated class. For example, we can use a different easing. So it won’t be linear. Another bonus here is that it will finish at the exact same time as the opacity animation.</p><p>Note that we have to do nothing during the animation, because it is done by JS thread. So we probably want to use <code>InteractionManager</code> here.</p><h2 id="check-it-out-in-the-savee-io">Check it out in the <a href="https://savee.io">Savee.io</a></h2><p>I wanted to build kind of playground for my animations and these articles. So I decided to build Savee — Financial Manager. During only 22 days, I have done <a href="https://itunes.apple.com/us/app/pineapple-financial-manager/id1369607032?ls=1&amp;mt=8" rel="noopener nofollow">iOS version</a>, <a href="https://play.google.com/store/apps/details?id=com.pineapple.android" rel="noopener nofollow">Android version</a>, <a href="https://savee.io/">website presentation</a> and wrote a <a href="https://medium.com/how-i-built-profitable-application-faster-than">How I built profitable application faster than found new job</a>! about that. Can’t say how much I enjoy this time. You should try it as well! If you want to support these articles (and me) you can buy the Pineapple. Just $2.99 a year. Nothing for you. Big motivation for me! Thank you 🙏</p><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h3 id="did-you-like-it-clap-comment-share-and-follow-me-"><strong>Did you like it? Clap, Comment, Share and Follow me! 👏</strong></h3><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-"><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>About me 👦</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></h3><p>I am an author of <a href="https://savee.io/">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz/">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a><br>📚 <em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em><br>🚧 <em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></p>]]></content:encoded></item><item><title><![CDATA[Animated Transition in React Native]]></title><description><![CDATA[You will learn how to do this beautiful transition effect in React Native.]]></description><link>https://blog.xotahal.cz/animated-transition-in-react-native/</link><guid isPermaLink="false">5bb01b59d9a4290c97a5acc4</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Sat, 24 Mar 2018 00:39:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/inspiration.gif" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2018/09/inspiration.gif" alt="Animated Transition in React Native"><p>Recently I’ve tried to get an inspiration for a next animation challenge. And here we go — <a href="https://medium.muz.li/ui-interactions-of-the-week-116-40eba84eb736" rel="noopener nofollow noopener">created by Ivan Parfenov</a>. I was curious if I am able to do this transition effect with React Native. <a href="https://expo.io/@xotahal/react-native-motion-example" rel="noopener nofollow noopener">You can check out a result on my expo account</a>!<strong><strong> </strong></strong>Why we even need the animations like these? Read <a href="https://uxdesign.cc/good-to-great-ui-animation-tips-7850805c12e5" rel="noopener nofollow noopener">Good to great UI animation tips</a> by Pablo Stanley.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*D35P0J6_34Yrs_n3i1hvjA.gif" class="kg-image" alt="Animated Transition in React Native"><figcaption>For <a href="https://dribbble.com/plates" data-href="https://dribbble.com/plates" class="markup--anchor markup--figure-anchor" rel="contact noopener noopener nofollow noopener" target="_blank" style="background-color: transparent; color: inherit; text-decoration: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0.54); background-image: linear-gradient(rgb(255, 255, 255) 50%, rgba(0, 0, 0, 0.54) 50%); background-repeat: repeat-x; background-size: 2px 2px; background-position: 0px 0.98em;">PLΛTES</a> by <a href="https://dribbble.com/parfenoff" data-href="https://dribbble.com/parfenoff" class="markup--anchor markup--figure-anchor" rel="contact noopener nofollow noopener" target="_blank" style="background-color: transparent; color: inherit; text-decoration: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0.54); background-image: linear-gradient(rgb(255, 255, 255) 50%, rgba(0, 0, 0, 0.54) 50%); background-repeat: repeat-x; background-size: 2px 2px; background-position: 0px 0.98em;">Ivan&nbsp;Parfenov</a></figcaption></figure><p>We can see there is a couple of animations. Toolbar tile (show/hide), bottom bar (show/hide), move a selected item, hide all others, show detail items and maybe even more.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*HdpUrmxtI0cptj8BpxsaPw.png" class="kg-image" alt="Animated Transition in React Native"><figcaption>Timeline of animations</figcaption></figure><p>The hard thing about the transition is to synchronize all of those animations. We can’t really unmount the List Page and show the Detail Page because we need to wait till all animations are done. Also, I am a fan of having a clean code. Easy to maintenance. If you have ever tried to implement an animation to your project, the code usually gets messy. Full of helper variables, crazy calculations, etc. That’s why I would like to introduce <a href="https://github.com/xotahal/react-native-motion" rel="nofollow noopener">react-native-motion</a>.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*nfm2A4bKidwuPQ-Oy4vTxQ.gif" class="kg-image" alt="Animated Transition in React Native"></figure><h2 id="an-idea-of-react-native-motion">An idea of react-native-motion</h2><p>Can you see the animation of toolbar’s title? You just need to move the title a bit and animate an opacity to zero/one. No big deal! But because of that, you need to write a code like this. Even before you actually start to write UI for that component.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/cd43f604de97f43c33e2111179ceb26f.js"></script><!--kg-card-end: html--><p>Now let’s take a look how we can use <a href="https://github.com/xotahal/react-native-motion" rel="nofollow noopener noopener">react-native-motion</a> for this. I know the animations are quite often very specific. And I know React Native provides very powerful Animated API. Anyway, it would be great to have a library with basic animations.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/89b4c744c6d88fe74a73c07afffa4a95.js"></script><!--kg-card-end: html--><h2 id="shared-element">Shared element</h2><p>The biggest problem of this challenge was moving of selected list item. The item that is shared between List Page and Detail Page. How to move the item from FlatList to the top of Detail’s Page when the element is actually not absolutely positioned? It is quite easy with react-native-motion.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/9dfb1daa8f0e79b7e7f91add8a4a3163.js"></script><!--kg-card-end: html--><p>We specified source element of the SharedElement on List Page. Now we need to do almost the same for destination element on the Detail Page. To know the position where we want to move the shared element.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/6490604fab7dd56b0626886af93a1555.js"></script><!--kg-card-end: html--><h2 id="where-is-the-magic">Where is the magic?</h2><p>How can we move a relatively positioned element from one page to the another one? Actually, we can’t. The SharedElement works like this:</p><p>- get a position of the source element<br>- get position of the destination element (obviously, without this step the animation can’t be initiated)<br>- create a clone of the shared element (The magic!)<br>- render a new layer above the screen<br>- render the cloned element that will cover the source element (in his position)<br>- initiate move to the destination position<br>- once the destination position was reached, remove the cloned element</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*MKDiUHnLdB7WiEPR26IHdw.png" class="kg-image" alt="Animated Transition in React Native"></figure><p>You can probably imagine there are 3 elements of the same React Node at the same moment. That’s because List Page is covered up by Detail Page during that moving animation. That’s why we can see all 3 elements. But we want to create an illusion that we actually moving the original source item.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/1000/1*m11vVsxY3Pa_e5lDMkOT_w.png" class="kg-image" alt="Animated Transition in React Native"><figcaption>SharedElement timeline</figcaption></figure><p>You can see point A and point B. That’s a time period when the moving is performing. You can also see the SharedElement fires some useful events. In this case, we use <code>WillStart</code> and <code>DidFinish</code> events. It is up to you to set an opacity for source and destination element to 0 when a moving to destination was initiated, and back to 1 for destination element once the animation was finished.</p><h2 id="what-do-you-think">What do you think?</h2><p>There is still work on <a href="https://github.com/xotahal/react-native-motion" rel="nofollow noopener">react-native-motion</a>. It is definitely not a final and stable version of this library. But it is a good start I hope :) I would love to hear what do you think about that!</p><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h3 id="did-you-like-it-clap-comment-share-and-follow-me-">Did you like it? Clap, Comment, Share and Follow me! 👏</h3><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-"><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>About me 👦</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></h3><p>I am an author of <a href="https://savee.io/">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz/">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a><br>📚 <em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em><br>🚧 <em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></p>]]></content:encoded></item><item><title><![CDATA[iOS Ripple Effect in React Native]]></title><description><![CDATA[You will learn how to create a RippleFeedback component that we can use for both Android and iOS.]]></description><link>https://blog.xotahal.cz/ios-ripple-effect-in-react-native/</link><guid isPermaLink="false">5bb01685d9a4290c97a5acc0</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Thu, 30 Nov 2017 00:19:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/stock-photo-71502811-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2018/09/stock-photo-71502811-1.jpg" alt="iOS Ripple Effect in React Native"><p>Hey guys! It’s been a while since I wrote an article about animation. I’ve needed to solve a problem with Ripple effect for iOS recently. Now, I'd like to share how I have done that with you guys.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*ufEj0zauCtr5k33FaWrAzg.gif" class="kg-image" alt="iOS Ripple Effect in React Native"></figure><blockquote><em>I am currently looking for a new job or project. If you need a help, with either React Native or React, let me know, please ;) I will be happy to help, learn, discuss, etc.<strong><strong> I am available to hire right now</strong></strong>! <em><em><em><em><em><em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></em></em></em></em></em> or </em><a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a></blockquote><h2 id="the-goal">The goal</h2><p>Create a RippleFeedback component that we can use for both Android and iOS. Since the Android version is pretty easy, using TouchableNativeFeedback, we won’t talk about it. Anyway, you can see it in <a href="https://github.com/xotahal/react-native-material-ui" rel="noopener nofollow">react-native-material-ui</a>.</p><h2 id="the-idea-">The idea 🤔</h2><p>We’ll get a content for a RippleFeedback component as children. In this case it’s a Button component. Then we need to create Background Layer (BL) and Ripple Layer (RL) which is represented by rounded View component (circle). Those views will be wrapped by TouchableWithoutFeedback component, because we still need to provide events like onPress, onLongPress, etc.</p><p>When I tried this feature on Android I noticed it behaves slightly different for onPress and onLongPress. You will see later in this text.</p><p>Immediately after onLongPress is called the BL is displayed. When user releases the button BL is animated to default value and in the same time starts Ripple animation (opacity to zero and scale value to 1).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*naHP9hhxntXkSDGbmkGWxQ.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>onLongPress</figcaption></figure><p>After onPress is called all of these animations happen in the same time. Opacity of BL is animated to maximum value, opacity of RL is animated to zero and RL’s scale value is animated to 1. After all of these animations are finished, BL is animated to default value (zero) and RL is reset to default values. Note that they are animated and reset. You will see why we don’t have to animate RL’s values.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*ufEj0zauCtr5k33FaWrAzg.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>onPress</figcaption></figure><h2 id="let-s-code-">Let’s code ✍️</h2><p>Here’s a skeleton of code with Views rendered in default mode. You can see default animated values in constructor. RL’s scale value (<code>scaleValue</code>) is set up to zero because we want it to start as a really small point (actually hidden point). And its opacity (<code>opacityRippleValue</code>) is set up to maxOpacity which is value between 0 and 1 (in this case it is 0.3). Last value is BL’s opacity (<code>opacityBackgroundValue</code>) which started as a hidden layer (value is set up to zero) and after user presses it is animated to max opacity and back to zero. It makes a blink effect.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/30c96e4332927f580f9c56e42e7a7410.js"></script><!--kg-card-end: html--><p>A children node is passed to this component as a content. We just need to render it inside of TouchableWithoutFeedback component.</p><p>Then we have a background layer (BL) and ripple layer (RL). BL is rendered in the same size as a container and RL is rendered as a circle with zero size by default. BL makes a blink effect and RL makes a ripple effect.</p><p>Notice an order of components. We don’t use zIndex. If we put children as a third child it would be over both layers Background and Ripple.</p><p>One more thing here — <code>pointerEvents</code>. For both layers BL and RL we set up this to <code>none</code> because we don’t want to get any events like an onPress. For container View, we set <code>box-none</code> which means we want to get only children events not events of container itself.</p><h2 id="let-s-animate">Let’s animate</h2><p>First of all we need to know the point where the Ripple Effect should start.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/bddce785155c3c7efd086340981f2d5d.js"></script><!--kg-card-end: html--><p>Immediately after user presses the button, we store a point where user tapped. And as you can see, in <em>renderRippleLayer</em>, we use this point to set up the position of RL. In other words we put a center of circle to this point. Just note that the circle has still zero size in this moment.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/c2f429ae98a78651ff86056229d39a06.js"></script><!--kg-card-end: html--><p>We’ll start with onPress event and only with Background Layer (blink effect). You can see Animated.parallel that runs all animations from array in the same time. It will make sense once we push RL Animation to array (next example). Line 6 animates opacity from zero (default value) to max opacity. Then after the animation is finished we need to animate value back to default. We can use start’s callback which is called exactly after the animation is finished. Now, we can animate opacity of BL back to default value. Here’s how the animation looks like without Ripple Animation. Blink!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*QKjRgle43F89XT04hzPIJA.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>Only Background Layer animation (Blink)</figcaption></figure><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/9e47f64a8a01cfd5732a9bcc1c65b2bd.js"></script><!--kg-card-end: html--><p>Let’s animate Ripple Layer. It’s the same onPress method. I’ve just commented what we’ve seen in previous example. Now, we animate RL’s opacity from default (maxOpacity) to zero and scale value from 0 to 1.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/72fc5b54eddfc4e7f312731dd09ac90b.js"></script><!--kg-card-end: html--><p>After is finished, we need to set those animations to default values to be ready on next press. That’s what <code>setDefaultAnimatedValues</code> does. We don’t have to animate the values back to defaults (we just set them). Because it’s actually hidden after animation is finished. See line 11 of previous example. We animated opacity to 0. That means it’s hidden and we can set those values immediately without animation. Ripple Effect without BL looks like this.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*y3pg-SVm_T2350NdnAqNWg.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>Only Ripple&nbsp;Effect</figcaption></figure><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/73f8ce0fe95c5a40ba27604f6ab20502.js"></script><!--kg-card-end: html--><p>And that’s it. It’s not so complicated, is it? Here’s both of animations together.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*ufEj0zauCtr5k33FaWrAzg.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>Both animation together</figcaption></figure><p>There’s still onLongPress animation remaining. Anyway, it’s almost the same like onPress animation. We just need to separate them. When user presses and holds the button we’ll display BL. That means we animate BL’s opacity from zero to max opacity. It seems like user holds the BL displayed during a holding of the button.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*WOaQlhxINrsBj2kosSAqMQ.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>Holding of the&nbsp;button</figcaption></figure><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/bcecc89a12d9f2e6d648764ce3a46878.js"></script><!--kg-card-end: html--><p>Then we make the magic in onPressOut method. Opacity and scale of RL’s is the same like in onPress. Only difference is we slowly animate BL’s opacity back to default value. We have done this step in start’s callback. But now, we have displayed BL in onLongPress already so we animate it back to default here, together with Ripple Effect. It looks like this.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*naHP9hhxntXkSDGbmkGWxQ.gif" class="kg-image" alt="iOS Ripple Effect in React Native"><figcaption>onLongPress animation</figcaption></figure><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/f781c741d42679c5385c92af75c4b20f.js"></script><!--kg-card-end: html--><h3 id="easy-peasy-">Easy peasy …</h3><p>I know, I know :) I needed that to be done for <a href="https://play.google.com/store/apps/details?id=com.reservio" rel="nofollow noopener">Reservio application</a> which uses <a href="https://github.com/xotahal/react-native-material-ui" rel="nofollow noopener">react-native-material-ui</a>. Anyway, I hope there is someone who appreciates this and maybe learn something new or just gets an inspiration. Or questions?</p><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h2 id="did-you-like-it-clap-comment-share-and-follow-me-"><strong><strong><strong>Did you like it? Clap, Comment, Share and Follow me! 👏</strong></strong></strong></h2><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-"><strong><strong><strong><strong><strong><strong><strong>About me 👦</strong></strong></strong></strong></strong></strong></strong></h3><p>I am an author of <a href="https://savee.io/">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz/">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a><br>📚 <em><em><em><em><em><em><em><em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em></em></em></em></em></em></em></em><br>🚧 <em><em><em><em><em><em><em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></em></em></em></em></em></em></p>]]></content:encoded></item><item><title><![CDATA[Toolbar Animation in React Native (2/2)]]></title><description><![CDATA[You will learn how to animate a background of Toolbar's search feature in React Native to look like as in Material Design by Google.]]></description><link>https://blog.xotahal.cz/toolbar-animation-in-react-native-part-2/</link><guid isPermaLink="false">5bb00b20d9a4290c97a5acbc</guid><category><![CDATA[Programming]]></category><category><![CDATA[React Native]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Mon, 06 Mar 2017 23:30:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/mio-design-2Fassets-2F1ekbPWQqJ5sMNvJ0om7XelfzOhaWMaeyM-2Ftopappbars-howtouse-1-1.png" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*6qwTpnnQqFI_PyGwPrsxRQ.gif" class="kg-image" alt="Toolbar Animation in React Native (2/2)"></figure><img src="https://blog.xotahal.cz/content/images/2018/09/mio-design-2Fassets-2F1ekbPWQqJ5sMNvJ0om7XelfzOhaWMaeyM-2Ftopappbars-howtouse-1-1.png" alt="Toolbar Animation in React Native (2/2)"><p><a href="https://blog.xotahal.cz/toolbar-animation-in-react-native-part1/">Last time</a>, we were talking about how to animate components that are displayed on toolbar (icons and title). Now, we’re going to talk about how to animate the background.</p><h2 id="idea">Idea</h2><p>It’s simple. And if there wasn’t this <a href="https://github.com/facebook/react-native/issues/6278" rel="nofollow noopener">issue</a> in React Native it would be even simpler.</p><p>We need two rounded Views that are displayed as a background of the Toolbar component. Let’s say we have Green one and White one (as we can see on the picture above). The Green one is scaled to 1 by default. And the White one is scaled to zero by default.</p><p>It would be great, if we could render them under left icon (Green one) and under search icon (White one). But we can’t. Because that <a href="https://github.com/facebook/react-native/issues/6278" rel="nofollow noopener">issue</a> in React Native. We can’t set scale to zero. Workaround is set scale to 0.01. But there would still be Green or White dot under the icon, because these rounded Views are pretty big. And that’s what we don’t want.</p><p>Here’s a workaround. We will put these rounded Views outside the bounds. It doesn’t follow the material design’s pattern, because it should start from the icon where a user presses, but it’s still good looking, isn’t it?</p><h2 id="let-s-code">Let’s code</h2><p>Here’s a code what you need to approach that animation.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/f5794a073df58b452102ba98512e8b20.js"></script><!--kg-card-end: html--><p>If you are interested in LeftElement, CenterElement and RightElement components, we were talking about them <a href="https://blog.xotahal.cz/toolbar-animation-in-react-native-part1/">last time</a>. In this code, there is onLayout callback, because we need to calculate how big should the rounded Views be. It depends on size of Toolbar, because we need to cover whole Toolbar component. Moreover, we need to cover it by only half of rounded View. Because it starts from side of Toolbar, not from center. And also we calculate with size of point that I mentioned above, in Idea section.</p><p>Now, we need to call onSearchOpenRequested method to animate scale value of the White background. After that animation, we set scale value of Green background to zero, because we want it to be ready to next animation. Note that the Green background is under the White background and user can’t see it. But when we set scale value of Green background to zero, we can switch zIndexes of Green and White backgrounds, so the Green one is above the White one now. But its scale value is set to zero, so user still can’t see the Green one. When we call onSearchCloseRequested, we repeat the process for Green background. We animate its scale value from zero to one. When the animation is completed (user sees the Green one), we can set scale value of White background to zero and move it above the Green background. Now we have everything ready to call onSearchOpenRequested again.</p><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h2 id="did-you-like-it-clap-comment-share-and-follow-me-"><strong>Did you like it? Clap, Comment, Share and Follow me! 👏</strong></h2><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-"><strong><strong><strong>About me 👦</strong></strong></strong></h3><p>I am an author of <a href="https://savee.io/">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz/">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a><br>📚 <em><em><em><em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em></em></em></em><br>🚧 <em><em><em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></em></em></p>]]></content:encoded></item><item><title><![CDATA[Toolbar Animation in React Native (1/1)]]></title><description><![CDATA[You will learn how to animate a Toolbar's search feature in React Native to look like as in Material Design by Google.]]></description><link>https://blog.xotahal.cz/toolbar-animation-in-react-native-part1/</link><guid isPermaLink="false">5baffc67d9a4290c97a5acb8</guid><category><![CDATA[Programming]]></category><category><![CDATA[React Native]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Sat, 28 Jan 2017 22:26:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/mio-design-2Fassets-2F1ekbPWQqJ5sMNvJ0om7XelfzOhaWMaeyM-2Ftopappbars-howtouse-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2018/09/mio-design-2Fassets-2F1ekbPWQqJ5sMNvJ0om7XelfzOhaWMaeyM-2Ftopappbars-howtouse-1.png" alt="Toolbar Animation in React Native (1/1)"><p>Today, we will talk about animation of Material Design’s Toolbar<em>.</em> As you can see in the picture below, we need to animate couple of Views together.</p><p>In this part, we will design the components and learn how to animate the text and icons. There’s going to be <a href="https://blog.xotahal.cz/toolbar-animation-in-react-native-part-2/">another article</a> that describes background animation. I think it will be more interesting part for you guys.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-images-1.medium.com/max/800/1*6qwTpnnQqFI_PyGwPrsxRQ.gif" class="kg-image" alt="Toolbar Animation in React Native (1/1)"><figcaption>Goal of this tutorial</figcaption></figure><p>You can also check <a href="https://github.com/xotahal/react-native-material-ui" rel="nofollow noopener"><strong><strong>react-native-material-ui</strong></strong></a> library, which already implements the Toolbar component. I’ve been using it for <a href="https://savee.io">Savee.io</a>.</p><h2 id="idea">Idea</h2><p>We will implement LeftElement, CenterElement, and RightElement<em>.</em> Then we have a Toolbar<em> </em>as a wrapper of those three components. There are two states. The search mode is either active or inactive. So we will animate a transition between them.</p><p>The first animation is a rotation of the LeftElement (arrow icon). The second animation is an opacity of CenterElement (title). We need both of the components to be re-rendered during the animation. LeftElement<em> </em>is changed from menu icon to arrow icon. CenterElement is changed from Text<em> </em>component to TextInput component.</p><h2 id="let-s-code">Let’s code</h2><p>First of all, we need to create a simple static View. No state, no animation.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*udKzY-w2rdS2dTh_NIbGCQ.gif" class="kg-image" alt="Toolbar Animation in React Native (1/1)"></figure><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/afae4a07dad016760955c07d6603d5df.js"></script><!--kg-card-end: html--><p>The LeftElement and RightElement components are almost the same. Note that the IconToggle component is included in the <a href="https://github.com/xotahal/react-native-material-ui" rel="nofollow noopener">react-native-material-ui</a> library. You can also check the <a href="https://blog.xotahal.cz/ripple-effect-in-react-native/">Ripple Effect Article</a> on this blog if you are interested in how it works.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/67b3aa015d8d5d519287b52f606dc9ce.js"></script><!--kg-card-end: html--><p>The CenterElement component is also quite simple.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/1c60aad076e5c02fa3391dac54bd39d2.js"></script><!--kg-card-end: html--><h2 id="let-s-add-the-state">Let’s add the state</h2><p>We have to add the state to the Toolbar that will control the animation. We can already use it for searching now but we want it to be more cool, right?</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*JTzFsEznY4qRP4zYD8nQPg.gif" class="kg-image" alt="Toolbar Animation in React Native (1/1)"></figure><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/dd2eb66ee6aa8a9664f0ec67eb657a7c.js"></script><!--kg-card-end: html--><p>After we press the right icon, we set <code>isSearchActive</code> to <code>true</code> and pass it to all components via props. Then we have to pass a value of TextInput to RightElement and show clear button if it’s needed. Here’s a code for right icon. You can change the left icon in a similar way.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/7ab42140cf85fe11b1311c53622e28a2.js"></script><!--kg-card-end: html--><h2 id="let-s-animate">Let’s animate</h2><p>We start with the left icon, which rotates and changes from menu to arrow. Then we animate the opacity of title. The right icon stays without animation. Sometimes, it’s better to do nothing.</p><figure class="kg-card kg-image-card"><img src="https://cdn-images-1.medium.com/max/800/1*Zrg_tsg2ythSkljqRWWAKQ.gif" class="kg-image" alt="Toolbar Animation in React Native (1/1)"></figure><h3 id="left-element">Left element</h3><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/bb3ba07ffc83c9f3029c8a153ffa03af.js"></script><!--kg-card-end: html--><p>We start to rotate menu icon to 90 degrees. Then we set leftElement to the arrow<em>.</em> It invokes re-render of the component and renders arrow instead of the menu. Then we can rotate arrow icon from 90 to 180 degrees. It would be better to have kind of micro animation over here but it’s not the goal of this article. Maybe next time?</p><p>The animation starts in componentWillReceiveProps where we check <code>isSearchActive</code> in props. We need to know if we animate from zero to 180 degrees or from 180 to zero.</p><p>It’s good to know about <a href="https://facebook.github.io/react-native/docs/animated.html" rel="nofollow noopener">Animated’s interpolate</a> function (line 40), which maps value to different value. It’s from number to degree in this case.</p><h3 id="center-element">Center element</h3><p>We change CenterElement in a similar way. We need to set the state in the half of the animation.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/451fe999b1546c92fb51567f5e34d78a.js"></script><!--kg-card-end: html--><p>We animate the opacity from 1 to zero. Then we set a <code>state.textInput</code> to <code>true</code>. It invokes re-render and renders TextInput component instead of Text<em>.</em> Note that the opacity is still set to zero. So we need to animate the opacity again. From zero to one.That’s all for now. Everything is ready to implement the background animation.</p><p><a href="https://blog.xotahal.cz/toolbar-animation-in-react-native-part-2/">Second part is here </a>— it is about how to animate the background of toolbar.</p><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h2 id="did-you-like-it-clap-comment-share-and-follow-me-">Did you like it? Clap, Comment, Share and Follow me! 👏</h2><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-"><strong>About me 👦</strong></h3><p>I am an author of <a href="https://savee.io/">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz/">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a><br>📚 <em><em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em></em><br>🚧 <em><em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></em></p>]]></content:encoded></item><item><title><![CDATA[Ripple Effect in React Native]]></title><description><![CDATA[You will learn how to use React Native's Animated API to build a Ripple Effect known from Google's Material Design.]]></description><link>https://blog.xotahal.cz/ripple-effect-in-react-native/</link><guid isPermaLink="false">5baa0819d9a4290c97a5acad</guid><category><![CDATA[React Native]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Jiri Otahal]]></dc:creator><pubDate>Tue, 17 Jan 2017 09:15:00 GMT</pubDate><media:content url="https://blog.xotahal.cz/content/images/2018/09/stock-photo-71502811.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.xotahal.cz/content/images/2018/09/stock-photo-71502811.jpg" alt="Ripple Effect in React Native"><p>This is a tutorial on how to make a ripple effect for Material Design’s Icon Button. We’ll use Animated API, which is a part of React Native.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.xotahal.cz/content/images/2018/09/ezgif.com-crop--1-.gif" class="kg-image" alt="Ripple Effect in React Native"><figcaption>Ripple effect</figcaption></figure><p>You can find an IconToggle component in open-source project called <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a>. If you want to rather see it in a real app you can check out the <a href="https://savee.io">Savee.io</a>!</p><h2 id="the-idea-">The idea 🤔</h2><p>We’ll make three Views. One of them as a container for IconToggle component. Another one as a container for ripple effect and last one as a container for Icon. We’ll wrap them in React Native’s TouchableWithoutFeedback component that fires onPressIn and onPressOut<em> </em>events.</p><p>Why do we need both of these events? Because there are two different animations. A scale animation and an opacity animation. They may run together, of course. So, is the onPressIn event enough? No. Because there could be a situation when the user presses the button for a longer time. Then we need scale animation to run first and wait for onPressOut event that runs opacity animation. It’s exactly how the icon button’s ripple effect works. I simulated that with the red star icon in the last example above.</p><h2 id="let-s-code-">Let’s code ✍️</h2><p>First of all, we’ll create a blank page for this example. Then we’ll create IconToggle component and the ripple effect animation. Finally, we’ll make some correlation.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/2884244a0eb1b75ce6940f654b56c3d5.js"></script><!--kg-card-end: html--><p>Now, we have a view with Toolbar which is known from Material Design by Google. The Toolbar is not a goal of this tutorial, so we took it from <a href="https://github.com/xotahal/react-native-material-ui/blob/master/src/Toolbar/Toolbar.react.js" rel="nofollow noopener">react-native-material-ui</a> library. Then, we put the IconToggle components and implement it in the following Gist.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/60553e73e92dc8da2f389eae20e96f6f.js"></script><!--kg-card-end: html--><p>Again, we took Icon component from <a href="https://github.com/xotahal/react-native-material-ui/blob/master/src/Icon/index.js" rel="nofollow noopener">react-native-material-ui</a>. Now, the animation.</p><h2 id="let-s-animate-">Let’s animate 😎</h2><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/55286987fec8fb7e81d1094ede3c7128.js"></script><!--kg-card-end: html--><p>On lines 14 and 15 we created two Animated.Values. One of them for scale<em> </em>animation and second for opacity animation. We pass them to Animated.View via its props. The scale animation begins inside of onPressedIn function, that is fired after the user presses icon. It starts from 0.01 (not zero) because there is an <a href="https://github.com/facebook/react-native/issues/6278" rel="nofollow noopener">issue</a> in React Native. Later, when the user releases the button, the opacity<em> </em>animation will start. It doesn’t matter if the scale animation is still running or not. After the opacity animation is done, we need Animated.Values to be set to init values (line 34). That’s it. That’s the whole ripple effect.</p><!--kg-card-begin: html--><script src="https://gist.github.com/xotahal/f6f25409203ff6cca37a5e568104b891.js"></script><!--kg-card-end: html--><p>In this code, we just added a color for icon and ripple effect. Look at line 12 and 18. We would like to use a native thread for Android platform (edit 2018: now you can also use the native thread for iOS as well) because then the animation doesn’t block the JS thread. In a real application we’ll probably fire onPress callback and there will be another code to run. We don’t want to block it, so it’s better to use native thread for animation.</p><h2 id="last-words">Last words  </h2><p><a href="https://gist.github.com/xotahal/d59616b9ee980d29842bc5c99d20134a" rel="nofollow noopener">You can find the whole code on my Github account</a>. Note that it’s not ready for production. For this purpose, you can use <a href="https://github.com/xotahal/react-native-material-ui" rel="nofollow noopener"><strong><strong>react-native-material-ui</strong></strong></a> that I’m developing as an open source library and using it <a href="http://www.reservio.com/" rel="nofollow noopener">t</a>o build the financial app called <a href="https://savee.io">Savee.io</a>.</p><hr><!--kg-card-begin: html--><div class="typeform-widget" data-url="https://xotahal.typeform.com/to/xxoruc" style="width: 100%; height: 500px;"></div> <script> (function() { var qs,js,q,s,d=document, gi=d.getElementById, ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm", b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id; js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })() </script> <div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5; padding-top: 5px;"> powered by <a href="https://admin.typeform.com/signup?utm_campaign=xxoruc&utm_source=typeform.com-13992783-Basic&utm_medium=typeform&utm_content=typeform-embedded-poweredbytypeform&utm_term=EN" style="color: #999" target="_blank">Typeform</a> </div><!--kg-card-end: html--><h3 id="did-you-like-it-clap-and-follow-me-">Did you like it? Clap and Follow me! 👏</h3><p>Actually you don’t have to do anything of that. But it will help me a lot. It’s a big motivation to the next work. Next articles like this for you guys.</p><h3 id="about-me-">About me 👦</h3><p>I am an author of <a href="https://savee.io">Savee.io</a> (which I also use as a playground for my animations 🤷‍). I open-sourced <a href="http://bit.ly/react-native-material-ui">react-native-material-ui</a> and <a href="http://bit.ly/react-native-motion">react-native-motion</a> libraries. Writing about them in this blog.</p><blockquote>If you need a help with your React Native app (animations, performance, etc.), let me know, please ;) I will be happy to discuss it.</blockquote><p>👦 <a href="https://xotahal.cz">Website</a><br>✍️ <a href="http://bit.ly/m-xotahal">Medium</a><br>🐦 <em><a href="http://bit.ly/t-xotahal" rel="nofollow noopener">Twitter</a></em><br>📚 <em><a href="http://bit.ly/github-xotahal" rel="nofollow noopener">Github</a></em><br>🚧 <em><a href="http://bit.ly/lin-xotahal" rel="nofollow noopener">LinkedIn</a></em></p>]]></content:encoded></item></channel></rss>