{"version":"https://jsonfeed.org/version/1","title":"Hashrocket - Mobile Posts","home_page_url":"https://hashrocket.com/blog","feed_url":"https://hashrocket.com/blog/tags/mobile.json","author":{"name":"Hashrocket","url":"https://hashrocket.com/","avatar":"https://hashrocket.com/favicon-228.png"},"items":[{"id":"https://hashrocket.com/blog/posts/creating-a-custom-mobile-integration-for-a-board-game-using-ruby-on-rails","url":"https://hashrocket.com/blog/posts/creating-a-custom-mobile-integration-for-a-board-game-using-ruby-on-rails","title":"Creating a Custom Mobile Integration for a Board Game Using Ruby on Rails","content_html":"Picture this: you find a charming old board game at a garage sale, bring it home, gather some friends—and snap. The 50-year-old plastic components break instantly. You search the web for help to replace this fun and unique game mechanic but there’s nothing to be found. So naturally, you roll up your sleeves and build your own mobile version. No one else does this? Just me? Well, in case you ever find yourself in a similar boat, I figured I would walk you through what I did when building my own mobile integration to the 1973 Parker Brothers classic [Billionare](https://boardgamegeek.com/boardgame/1436/billionaire).\n\nAs I said, right when I went to try out this cool \"new\" board game for the first time, the plastic ends of the `Analyzer` snapped. The analyzer is basically a plastic rod with 2  floating spinners on them. The spinners, when rotated, will either land with a red face or a green face. You then refer to the chart to see what action to take. I thought this was such a unique way to give a random effect in a game, without relying on dice. It essentially is just a random binary spinner that counts up to 4. Here is what it looks like for reference:\r\n\r\n![image](https://i.imgur.com/rKJADkM.png)\r\n\r\nSo, without any 4 sided die lying around, and not wanting to use a boring random number generator, my brain went right to what it knows best---Ruby on Rails.\r\n\r\nSo without further ado, here's what I did and how you can do something similar yourself.\r\n\r\n# Creating the app\r\n\r\nSure, Rails could be considered overkill for such a simple app. But my idea is to allow this project to scale into a whole library of board game helpers that can all live within the same app. So, to start off I ran the old trusty `rails new` command, with a couple preferences I like to pass in to make my life easier as a developer.\r\n\r\n```ruby\r\nrails new board_game_library --css tailwind --database=postgresql\r\n```\r\n\r\nOne of the main tools I leveraged for this project besides Rails was [Tailwind](https://www.tailwindcss.com). Tailwind makes styling so easy. Here at Hashrocket Tailwind is pretty standard for all of us, so if you're interested in any tips or tricks, we have plenty of [blog posts](https://hashrocket.com/blog/search?utf8=%E2%9C%93\u0026search_term=tailwind) and [TILs](https://til.hashrocket.com/?q=tailwind) worth checking out!\r\n\r\nThe app itself is very simple. Here is everything I needed to do:\r\n\r\n- Create a view to host the Analyzer\r\n- Create a stimulus controller to \"scramble\" the Analyzer\r\n- Expose `ngrok` as a host in the config so I could access the Analyzer from my phone for free\r\n\r\n# The View\r\n\r\nThe view is nothing revolutionary. I just wanted a simple interface that gave me all the capabilities of the Analyzer from the board game. So, I needed 2 \"spinners\", a way to spin them, and a chart that let you know what action to take.\r\n\r\n## Spinners\r\nHere is the html for the spinners. Simply 2 boxes side by side that have some `data-analyzer-target`s that are used by the stimulus controller. I also give them some default colors here to give the user an idea of what to expect when the app opens up.\r\n\r\n```html\r\n\u003cdiv class=\"flex space-x-4\"\u003e\r\n  \u003cdiv class=\"bg-red-400 w-1/2 h-24\" data-analyzer-target=\"left\"\u003e\r\n  \u003c/div\u003e\r\n\r\n  \u003cdiv class=\"bg-green-400 w-1/2 h-24\" data-analyzer-target=\"right\"\u003e\r\n  \u003c/div\u003e\r\n\u003c/div\u003e\r\n```\r\n\r\n## Spinner button\r\nNext we have the call to action, the \"spinner\" button. This is simply a nicely styled button that will call the `randomize` method on the stimulus controller.\r\n\r\n```html\r\n\u003cdiv class=\"w-fit mx-auto mt-12\"\u003e\r\n  \u003cbutton class=\"border border-black rounded-md shadow-lg p-2\" data-action=\"click-\u003eanalyzer#randomize\" data-analyzer-target=\"analyzer\"\u003e\r\n    ANALYZE\r\n  \u003c/button\u003e\r\n\u003c/div\u003e\r\n```\r\n\r\n## Actions Chart\r\nThe actions chart is just simply a bunch of elements of text, styled with html, along with a visual representation of the matching result. I'll give an example of one, but to save screen space on this post, I won't post the whole thing. Remember, you can always check out the source code [here](https://github.com/vanillaHafer/billionare-analyzer/tree/main).\r\n\r\n```html\r\n\u003cdiv class=\"mt-12\"\u003e\r\n  \u003cdiv class=\"w-fit mx-auto border border-black rounded-lg p-4 space-y-4\"\u003e\r\n    \u003cdiv class=\"flex space-x-6\"\u003e\r\n      \u003cdiv class=\"flex space-x-1 my-auto\"\u003e\r\n        \u003cdiv class=\"w-8 h-4 bg-red-400 border border-black\"\u003e\u003c/div\u003e\r\n        \u003cdiv class=\"w-8 h-4 bg-red-400 border border-black\"\u003e\u003c/div\u003e\r\n      \u003c/div\u003e\r\n\r\n      \u003cdiv\u003e\r\n        Take investment you are analyzing.\r\n      \u003c/div\u003e\r\n    \u003c/div\u003e\r\n\r\n    \u003c!-- Other divs for the other outcomes --\u003e\r\n\u003c/div\u003e\r\n```\r\n\r\n# The Controller\r\n\r\nFor my stimulus controller I gave it the targets you saw in the examples above, as well as some functions to help us randomize. Here is a high-level view of a few of the methods. If you want to see the code for yourself, please check out the [repo here](https://github.com/vanillaHafer/billionare-analyzer/tree/main):\r\n\r\n- `randomize()` **Called via the Analyze button. Kicks off the randomization, or *spinning***\r\n- `disableButton()` **Disables the Analyze button**\r\n- `randomAnimation()` **Starts animating the *left* and *right* spinners on the page**\r\n- `makeDecision()` **Determine via 50% chance for each spinner whether it will be red or green**\r\n- `enableButton()` **Enable the Analyze button when everything is finished**\r\n\r\n# Accessing from my phone\r\n\r\nFor the final piece of the puzzle, I wanted a way to easily view this from my phone so I didn't need to bring a big laptop or something to the table. So, for a simple and easy way to host this \"on the web\" without actually paying for a domain and setting all that up, I used the free version of [ngrok](https://ngrok.com/). Now, for this to work properly with your Rails app, you will need to add one line to your `config/application.rb` file.\r\n\r\n```ruby\r\n#config/application.rb\r\n\r\n# ...\r\nconfig.hosts \u003c\u003c \".ngrok-free.app\"\r\n# ...\r\n```\r\n\r\nThis allows any hosts that end with `.ngrok-free.app` to have access to the application. This way you can start and stop ngrok as much as you wish, and you don't need to manually input the random host in every time.\r\n\r\nNow simply start your rails server, start up ngrok, and access it from your phone or any other device and you should have something like this as your final product:\r\n\r\n\u003cimg src=\"https://i.imgur.com/9MZ63Vf.gif\" width=\"250px\"\u003e\r\n# Conclusion\r\n\r\nSo, this ended up being a fun way to play the game with some friends. It worked exactly as expected and it was also really cool to be playing a 50 year old board game that had its own custom mobile integration, even if it was small and simple.\r\n\r\nDon't want to go through all the work to make your own Rails app? Feel free to reach out to Hashrocket for your next project! Big or small, we'd love to hear about how we can help you make the app you want to get the results you need!\r\n\r\n\u003chr /\u003e\r\n      \r\nCover Photo by [Thomas Buchhol](https://unsplash.com/@markusspiske) on [Unsplash](https://unsplash.com/photos/a-close-up-of-a-bunch-of-buttons-on-a-table-0n7_eiAQZwA?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText\"). \r\n\r\nAnalyzer image provided by [Thomas Melinsky](https://boardgamegeek.com/profile/mithras) on [BoardGameGeek](https://boardgamegeek.com/image/776001/billionaire).","content_text":"Picture this: you find a charming old board game at a garage sale, bring it home, gather some friends—and snap. The 50-year-old plastic components break instantly. You search the web for help to replace this fun and unique game mechanic but there’s nothing to be found. So naturally, you roll up your sleeves and build your own mobile version. No one else does this? Just me? Well, in case you ever find yourself in a similar boat, I figured I would walk you through what I did when building my own mobile integration to the 1973 Parker Brothers classic Billionare.\n\nAs I said, right when I went to try out this cool \"new\" board game for the first time, the plastic ends of the Analyzer snapped. The analyzer is basically a plastic rod with 2  floating spinners on them. The spinners, when rotated, will either land with a red face or a green face. You then refer to the chart to see what action to take. I thought this was such a unique way to give a random effect in a game, without relying on dice. It essentially is just a random binary spinner that counts up to 4. Here is what it looks like for reference:\n\n\n\nSo, without any 4 sided die lying around, and not wanting to use a boring random number generator, my brain went right to what it knows best---Ruby on Rails.\n\nSo without further ado, here's what I did and how you can do something similar yourself.\nCreating the app\n\nSure, Rails could be considered overkill for such a simple app. But my idea is to allow this project to scale into a whole library of board game helpers that can all live within the same app. So, to start off I ran the old trusty rails new command, with a couple preferences I like to pass in to make my life easier as a developer.\nrails new board_game_library --css tailwind --database=postgresql\n\nOne of the main tools I leveraged for this project besides Rails was Tailwind. Tailwind makes styling so easy. Here at Hashrocket Tailwind is pretty standard for all of us, so if you're interested in any tips or tricks, we have plenty of blog posts and TILs worth checking out!\n\nThe app itself is very simple. Here is everything I needed to do:\n\n\nCreate a view to host the Analyzer\nCreate a stimulus controller to \"scramble\" the Analyzer\nExpose ngrok as a host in the config so I could access the Analyzer from my phone for free\n\nThe View\n\nThe view is nothing revolutionary. I just wanted a simple interface that gave me all the capabilities of the Analyzer from the board game. So, I needed 2 \"spinners\", a way to spin them, and a chart that let you know what action to take.\nSpinners\n\nHere is the html for the spinners. Simply 2 boxes side by side that have some data-analyzer-targets that are used by the stimulus controller. I also give them some default colors here to give the user an idea of what to expect when the app opens up.\n\u0026lt;div class=\"flex space-x-4\"\u0026gt;\n  \u0026lt;div class=\"bg-red-400 w-1/2 h-24\" data-analyzer-target=\"left\"\u0026gt;\n  \u0026lt;/div\u0026gt;\n\n  \u0026lt;div class=\"bg-green-400 w-1/2 h-24\" data-analyzer-target=\"right\"\u0026gt;\n  \u0026lt;/div\u0026gt;\n\u0026lt;/div\u0026gt;\nSpinner button\n\nNext we have the call to action, the \"spinner\" button. This is simply a nicely styled button that will call the randomize method on the stimulus controller.\n\u0026lt;div class=\"w-fit mx-auto mt-12\"\u0026gt;\n  \u0026lt;button class=\"border border-black rounded-md shadow-lg p-2\" data-action=\"click-\u0026gt;analyzer#randomize\" data-analyzer-target=\"analyzer\"\u0026gt;\n    ANALYZE\n  \u0026lt;/button\u0026gt;\n\u0026lt;/div\u0026gt;\nActions Chart\n\nThe actions chart is just simply a bunch of elements of text, styled with html, along with a visual representation of the matching result. I'll give an example of one, but to save screen space on this post, I won't post the whole thing. Remember, you can always check out the source code here.\n\u0026lt;div class=\"mt-12\"\u0026gt;\n  \u0026lt;div class=\"w-fit mx-auto border border-black rounded-lg p-4 space-y-4\"\u0026gt;\n    \u0026lt;div class=\"flex space-x-6\"\u0026gt;\n      \u0026lt;div class=\"flex space-x-1 my-auto\"\u0026gt;\n        \u0026lt;div class=\"w-8 h-4 bg-red-400 border border-black\"\u0026gt;\u0026lt;/div\u0026gt;\n        \u0026lt;div class=\"w-8 h-4 bg-red-400 border border-black\"\u0026gt;\u0026lt;/div\u0026gt;\n      \u0026lt;/div\u0026gt;\n\n      \u0026lt;div\u0026gt;\n        Take investment you are analyzing.\n      \u0026lt;/div\u0026gt;\n    \u0026lt;/div\u0026gt;\n\n    \u0026lt;!-- Other divs for the other outcomes --\u0026gt;\n\u0026lt;/div\u0026gt;\nThe Controller\n\nFor my stimulus controller I gave it the targets you saw in the examples above, as well as some functions to help us randomize. Here is a high-level view of a few of the methods. If you want to see the code for yourself, please check out the repo here:\n\n\nrandomize() Called via the Analyze button. Kicks off the randomization, or *spinning*\ndisableButton() Disables the Analyze button\nrandomAnimation() Starts animating the left and right spinners on the page\nmakeDecision() Determine via 50% chance for each spinner whether it will be red or green\nenableButton() Enable the Analyze button when everything is finished\n\nAccessing from my phone\n\nFor the final piece of the puzzle, I wanted a way to easily view this from my phone so I didn't need to bring a big laptop or something to the table. So, for a simple and easy way to host this \"on the web\" without actually paying for a domain and setting all that up, I used the free version of ngrok. Now, for this to work properly with your Rails app, you will need to add one line to your config/application.rb file.\n#config/application.rb\n\n# ...\nconfig.hosts \u0026lt;\u0026lt; \".ngrok-free.app\"\n# ...\n\nThis allows any hosts that end with .ngrok-free.app to have access to the application. This way you can start and stop ngrok as much as you wish, and you don't need to manually input the random host in every time.\n\nNow simply start your rails server, start up ngrok, and access it from your phone or any other device and you should have something like this as your final product:\n\n\nConclusion\n\nSo, this ended up being a fun way to play the game with some friends. It worked exactly as expected and it was also really cool to be playing a 50 year old board game that had its own custom mobile integration, even if it was small and simple.\n\nDon't want to go through all the work to make your own Rails app? Feel free to reach out to Hashrocket for your next project! Big or small, we'd love to hear about how we can help you make the app you want to get the results you need!\n\n\n\nCover Photo by Thomas Buchhol on Unsplash. \n\nAnalyzer image provided by Thomas Melinsky on BoardGameGeek.\n","summary":"Picture this: you find a charming old board game at a garage sale, bring it home, gather some friends—and snap. The 50-year-old plastic components break instantly. You search the web for help to replace this fun and unique game mechanic but there’s nothing to be found. So naturally, you roll up your sleeves and build your own mobile version. No one else does this? Just me? Well, in case you ever find yourself in a similar boat, I figured I would walk you through what I did when building my own mobile integration to the 1973 Parker Brothers classic Billionare.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/1073/bg.jpg","date_published":"2025-12-04T09:00:00-05:00","data_modified":"2025-11-14T11:53:48-05:00","author":{"name":"Craig Hafer","url":"https://hashrocket.com/team/craig-hafer","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/108/IMG_4001.jpg"},"tags":["Ruby","Mobile","rails","board game app"]},{"id":"https://hashrocket.com/blog/posts/nativewind-speeding-up-styling-in-react-native","url":"https://hashrocket.com/blog/posts/nativewind-speeding-up-styling-in-react-native","title":"Nativewind: Speeding up Styling in React Native","content_html":"How Nativewind can speed up your React Native Development\n\n\r\nIf you're anything like me, after working on a few web projects with Tailwind, it can feel like a drag to return to stacks that use other styling libraries. Tailwind has become, for myself, and many other developers, a standard styling paradigm. When starting my most recent React Native project, I was relieved to find out that NativeWind exists. NativeWind is exactly what is sounds like: Tailwind Classes in React Native. I can attest to the breeziness of writing an entire native app without a single call to StyleSheet.create.\r\n\r\n## It's Familiar\r\nNativewind takes the familiar classes of Tailwind CSS directly to your React Native components. Virtually every* class from Tailwind CSS can be used the exact same way on your mobile app (and the web), and the development results end up being faster iteration, less translating, and components that feel more readable and maintainable.\r\n\r\nLet’s look at how to set it up\r\n\r\nNativeWind translates Tailwind class names into React Native styles at runtime or compile-time, if you use the Babel plugin. You end up with the the same composable mindset of Tailwind, but the output is just React Native styles.\r\n\r\nThe setup is simple enough, for my latest project we used expo:\r\n\r\n```\r\nnpx expo install nativewind react-native-reanimated@~3.17.4 react-native-safe-area-context@5.4.0\r\nnpx expo install --dev tailwindcss@^3.4.17 prettier-plugin-tailwindcss@^0.5.11\r\n```\r\n\r\nNow to generate a tailwind config, run:\r\n\r\n```\r\nnpx tailwindcss init\r\n```\r\n\r\nBe sure to include the path to your components in the generated tailwind.config.js file\r\n\r\n```javascript\r\n/** @type {import('tailwindcss').Config} */\r\nmodule.exports = {\r\n  content: [\"./App.tsx\", \"./components/**/*.{js,jsx,ts,tsx}\"],\r\n  presets: [require(\"nativewind/preset\")],\r\n  theme: {\r\n    extend: {},\r\n  },\r\n  plugins: [],\r\n}\r\n```\r\n\r\nNext create your global.css file with tailwind's directives\r\n\r\n```css\r\n@tailwind base;\r\n@tailwind components;\r\n@tailwind utilities;\r\n```\r\n\r\nThen, enable the Babel plugin in babel.config.js:\r\n\r\n```jsx\r\nmodule.exports = function (api) {\r\n  api.cache(true);\r\n  return {\r\n    presets: [\r\n      [\"babel-preset-expo\", { jsxImportSource: \"nativewind\" }],\r\n      \"nativewind/babel\",\r\n    ],\r\n  };\r\n};\r\n```\r\n\r\n\r\nNow you’re ready to use all the classes Nativewind provides in your components:\r\n\r\n```jsx\r\nimport { View, Text, Pressable } from 'react-native'\r\n\r\nexport default function MyComponent() {\r\n  return (\r\n    \u003cView className=\"flex-1 items-center justify-center bg-gray-100\"\u003e\r\n      \u003cText className=\"text-2xl font-semibold text-gray-900 mb-4\"\u003e\r\n        Hello world, this component is using NativeWind!\r\n      \u003c/Text\u003e\r\n      \u003cPressable className=\"bg-blue-400 px-4 py-2 rounded-lg active:bg-blue-600\"\u003e\r\n        \u003cText className=\"text-white font-medium\"\u003ePress me\u003c/Text\u003e\r\n      \u003c/Pressable\u003e\r\n    \u003c/View\u003e\r\n  )\r\n}\r\n```\r\n\r\nYou will probably want to create some custom tailwind colors/classes, which you can include into the existing theme.\r\n\r\n```jsx\r\n//tailwind.config.js\r\n\r\nimport { colors } from \"./theme/colors\"\r\nmodule.exports = {\r\n  theme: {\r\n    extend: {\r\n      colors: colors\r\n      },\r\n    },\r\n  },\r\n}\r\n```\r\n\r\nFor more information on installing Nativewind, be sure to check out the [documentation](https://www.nativewind.dev/docs/getting-started/installation)\r\n\r\nDefining style objects in React Native can spiral, and to be fair, so can inline tailwind classes at times. The separation of style sheets can look neat at first, but over time, it can become another layer to maintain, a long list of key names that rarely get reused across files when not carefully organized.\r\n\r\nLet's compare StyleSheets with Nativewind\r\n\r\n```jsx\r\nconst styles = StyleSheet.create({\r\n  container: {\r\n    flex: 1,\r\n    backgroundColor: '#f9fafb',\r\n    justifyContent: 'center',\r\n    alignItems: 'center',\r\n  },\r\n})\r\n```\r\n\r\n\r\nNow compare that to this:\r\n\r\n```jsx\r\n\u003cView className=\"flex-1 bg-gray-50 justify-center items-center\" /\u003e\r\n```\r\n\r\n\r\nThe result is the same, and I'd argue the tailwind is more readable.\r\n\r\nI prefer never having to context switch between the code I'm writing and the styles it uses. Navigating to the bottom of the file just to tweak a component's padding can be tedious.\r\n\r\nAs a developer that uses Tailwind on the web, Nativewind makes me feel right at home. It also means that If you plan on distributing your native app to the web, it's simple to use Tailwind breakpoints to alter the design of your components for larger screens.\r\n\r\n## Integration\r\n\r\nNativewind also plays well with other libraries. Since the generated output is just standard React Native styles, you can still use other animation and navigation libraries. Essentially, if it takes a className prop, you can throw Nativewind styles at it.\r\n\r\n```\r\nimport { MotiView } from 'moti'\r\n\r\n\u003cMotiView\r\n  from={{ opacity: 0, translateY: 8 }}\r\n  animate={{ opacity: 1, translateY: 0 }}\r\n  className=\"p-4 bg-brand-500 rounded-xl\"\r\n/\u003e\r\n```\r\n\r\nAnother great feature is that the basic animation classes included with Tailwind work with Nativewind. At the time of writing this the support is considered experimental, however in my experience all of the ```animate-``` classes work as expected on IOS and Android.\r\n\r\n\r\n## In Conclusion\r\n\r\nThe familiar Tailwind class syntax and easily achieved responsiveness make Nativewind an effective library for speeding up react native development.\r\n\r\nIf you’re tired of jumping back and forth from component renders and StyleSheets, I highly recommend seeing if Nativewind can improve your workflow on your next React Native Project.\r\n\r\n## Work with us\r\n\r\nNeed help with your next React Native project? Don't hesitate to reach out with any questions.","content_text":"How Nativewind can speed up your React Native Development\n\nIf you're anything like me, after working on a few web projects with Tailwind, it can feel like a drag to return to stacks that use other styling libraries. Tailwind has become, for myself, and many other developers, a standard styling paradigm. When starting my most recent React Native project, I was relieved to find out that NativeWind exists. NativeWind is exactly what is sounds like: Tailwind Classes in React Native. I can attest to the breeziness of writing an entire native app without a single call to StyleSheet.create.\nIt's Familiar\n\nNativewind takes the familiar classes of Tailwind CSS directly to your React Native components. Virtually every* class from Tailwind CSS can be used the exact same way on your mobile app (and the web), and the development results end up being faster iteration, less translating, and components that feel more readable and maintainable.\n\nLet’s look at how to set it up\n\nNativeWind translates Tailwind class names into React Native styles at runtime or compile-time, if you use the Babel plugin. You end up with the the same composable mindset of Tailwind, but the output is just React Native styles.\n\nThe setup is simple enough, for my latest project we used expo:\nnpx expo install nativewind react-native-reanimated@~3.17.4 react-native-safe-area-context@5.4.0\nnpx expo install --dev tailwindcss@^3.4.17 prettier-plugin-tailwindcss@^0.5.11\n\nNow to generate a tailwind config, run:\nnpx tailwindcss init\n\nBe sure to include the path to your components in the generated tailwind.config.js file\n/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  content: [\"./App.tsx\", \"./components/**/*.{js,jsx,ts,tsx}\"],\n  presets: [require(\"nativewind/preset\")],\n  theme: {\n    extend: {},\n  },\n  plugins: [],\n}\n\nNext create your global.css file with tailwind's directives\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\nThen, enable the Babel plugin in babel.config.js:\nmodule.exports = function (api) {\n  api.cache(true);\n  return {\n    presets: [\n      [\"babel-preset-expo\", { jsxImportSource: \"nativewind\" }],\n      \"nativewind/babel\",\n    ],\n  };\n};\n\nNow you’re ready to use all the classes Nativewind provides in your components:\nimport { View, Text, Pressable } from 'react-native'\n\nexport default function MyComponent() {\n  return (\n    \u0026lt;View className=\"flex-1 items-center justify-center bg-gray-100\"\u0026gt;\n      \u0026lt;Text className=\"text-2xl font-semibold text-gray-900 mb-4\"\u0026gt;\n        Hello world, this component is using NativeWind!\n      \u0026lt;/Text\u0026gt;\n      \u0026lt;Pressable className=\"bg-blue-400 px-4 py-2 rounded-lg active:bg-blue-600\"\u0026gt;\n        \u0026lt;Text className=\"text-white font-medium\"\u0026gt;Press me\u0026lt;/Text\u0026gt;\n      \u0026lt;/Pressable\u0026gt;\n    \u0026lt;/View\u0026gt;\n  )\n}\n\nYou will probably want to create some custom tailwind colors/classes, which you can include into the existing theme.\n//tailwind.config.js\n\nimport { colors } from \"./theme/colors\"\nmodule.exports = {\n  theme: {\n    extend: {\n      colors: colors\n      },\n    },\n  },\n}\n\nFor more information on installing Nativewind, be sure to check out the documentation\n\nDefining style objects in React Native can spiral, and to be fair, so can inline tailwind classes at times. The separation of style sheets can look neat at first, but over time, it can become another layer to maintain, a long list of key names that rarely get reused across files when not carefully organized.\n\nLet's compare StyleSheets with Nativewind\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: '#f9fafb',\n    justifyContent: 'center',\n    alignItems: 'center',\n  },\n})\n\nNow compare that to this:\n\u0026lt;View className=\"flex-1 bg-gray-50 justify-center items-center\" /\u0026gt;\n\nThe result is the same, and I'd argue the tailwind is more readable.\n\nI prefer never having to context switch between the code I'm writing and the styles it uses. Navigating to the bottom of the file just to tweak a component's padding can be tedious.\n\nAs a developer that uses Tailwind on the web, Nativewind makes me feel right at home. It also means that If you plan on distributing your native app to the web, it's simple to use Tailwind breakpoints to alter the design of your components for larger screens.\nIntegration\n\nNativewind also plays well with other libraries. Since the generated output is just standard React Native styles, you can still use other animation and navigation libraries. Essentially, if it takes a className prop, you can throw Nativewind styles at it.\nimport { MotiView } from 'moti'\n\n\u0026lt;MotiView\n  from={{ opacity: 0, translateY: 8 }}\n  animate={{ opacity: 1, translateY: 0 }}\n  className=\"p-4 bg-brand-500 rounded-xl\"\n/\u0026gt;\n\nAnother great feature is that the basic animation classes included with Tailwind work with Nativewind. At the time of writing this the support is considered experimental, however in my experience all of the animate- classes work as expected on IOS and Android.\nIn Conclusion\n\nThe familiar Tailwind class syntax and easily achieved responsiveness make Nativewind an effective library for speeding up react native development.\n\nIf you’re tired of jumping back and forth from component renders and StyleSheets, I highly recommend seeing if Nativewind can improve your workflow on your next React Native Project.\nWork with us\n\nNeed help with your next React Native project? Don't hesitate to reach out with any questions.\n","summary":"How Nativewind can speed up your React Native Development\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/1035/ChatGPT_Image_Oct_31__2025__06_39_05_PM%282%29.png","date_published":"2025-11-13T09:00:00-05:00","data_modified":"2025-10-31T18:43:52-04:00","author":{"name":"Jack Rosa","url":"https://hashrocket.com/team/jackrosa","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/112/headshot.jpg"},"tags":["Mobile","React Native"]},{"id":"https://hashrocket.com/blog/posts/expo-for-react-native-in-2025-a-perspective","url":"https://hashrocket.com/blog/posts/expo-for-react-native-in-2025-a-perspective","title":"Expo for React Native in 2025: A Perspective","content_html":"The React Native ecosystem has improved significantly over the years, and Expo has evolved from a beginner friendly wrapper into a robust mobile framework. Native developers face an important decision when starting a project: should you build your React Native app with Expo, or go the bare React Native route? Let's explore the advantages and concerns to help you make an informed choice.\n\n## What is Expo?\r\n\r\nFor those new to the ecosystem, Expo is a framework and platform built around React Native that provides a set of tools and services to drastically simplify mobile app development. It offers a workflow that abstracts virtually all of the native code configuration and a bare workflow for those who need more control over native code directories.\r\n\r\n## The Advantages: Why Expo Shines in 2025\r\n\r\n### Rapid Development and Iteration\r\n\r\nThe strongest advantage of Expo is its ability to accelerate development. With Expo Go, developers can test apps on physical devices without complex build processes. The development experience with Expo Go is immediate, you write code, save, and see the changes almost instantly on your device.\r\n\r\nOver-the-air (OTA) updates through EAS (Expo Application Services) Update allow you to push JavaScript updates directly to users without having to go through the app store review process. For patches, bug fixes, and non-native changes, this is a game changer.\r\n\r\n### EAS (Expo Application Services)\r\n\r\nEAS has matured into a comprehensive suite of cloud services that rival any CI/CD platform. EAS Build handles iOS and Android builds in the cloud. EAS Submit automates app store submissions, and EAS Update manages over the air deployments.\r\n\r\nFor teams without dedicated DevOps resources, EAS is simple enough to manage the build and submission processes.\r\n\r\n### Rich SDK and Native Modules\r\n\r\nThe expo-modules API provides tested and documented modules for camera access, location services, push notifications, and dozens of other features. These modules work consistently across platforms and are maintained by the Expo team. There is also the option to write your own custom native modules if you need to.\r\n\r\n### Superior Developer Experience\r\n\r\nThe tooling ecosystem around Expo is excellent. Expo CLI provides intuitive commands, helpful error messages, and streamlined workflows. The documentation is comprehensive and regularly updated. TypeScript support is first-class, with excellent type definitions across the entire SDK.\r\n\r\nMetro bundler configuration, app config management, and environment variable handling are all significantly simpler with Expo's opinionated approach.\r\n\r\n### Cross-Platform Consistency\r\n\r\nExpo's modules are designed with cross-platform consistency in mind. Behavioral differences between iOS and Android are minimized, and APIs are designed to feel natural on both platforms. This reduces the \"write once, debug everywhere\" problem that sometimes occurs in React Native development.\r\n\r\n## The Concerns: Where Expo Falls Short\r\n\r\n### Cost Considerations\r\n\r\nWhile Expo's open source tools are free, EAS services operate on a pricing model that scales with usage. For hobbyists and small projects, the free tier is a decent offering. However, for larger teams or apps with frequent builds, costs can accumulate quickly. Build minutes, submission operations, and bandwidth for updates all factor into the pricing for EAS.\r\n\r\n### Native Module Limitations\r\n\r\nDespite constant improvements, there are still scenarios where Expo's abstraction layer gets in the way. Some third-party libraries with native dependencies don't support Expo out of the box. While you can use custom development builds or config plugins to integrate most libraries, this can add lot of complexity and convolute what was a simplified workflow. \r\n\r\nHighly specialized apps with unique native requirements may find themselves fighting against Expo's conventions rather than benefiting from them.\r\n\r\n### Dependency on Expo's Ecosystem\r\n\r\nChoosing Expo means buying into their ecosystem and release cycle. You're dependent on Expo's team to maintain modules, update dependencies, and support new React Native versions. While they have a strong track record, there's always some risk when tying your app's foundation to a third-party framework.\r\n\r\nSDK upgrades can sometimes be breaking, requiring code changes across your application. While Expo provides upgrade helpers and documentation, migrating between major versions still requires testing and validation.\r\n\r\n### Learning Curve for Native Development\r\n\r\nExpo's abstraction layer can be a double-edged sword. Expo lowers the barrier to entry, but developers who exclusively use Expo may find themselves lacking the deep native knowledge needed to solve issues when they arise at the native level. Debugging can be challenging without understanding of Xcode, Android Studio, and native build systems.\r\n\r\nTeams may find themselves stuck when facing edge cases that require native-level debugging or customization.\r\n\r\n### OTA Update Limitations\r\n\r\nWhile OTA updates are powerful, they have important constraints. You can only update JavaScript code and assets while native code changes will require a full app store submission. Large JavaScript bundles can also make OTA updates slow on poor network connections.\r\n\r\nThere are also compliance considerations. Some app store review processes scrutinize apps that update their code outside of the review process, particularly in regulated industries.\r\n\r\n## What's right for your project?\r\n\r\n**Expo is an excellent choice when:**\r\n\r\n- You're building a standard app without exotic native requirements\r\n- Your team values rapid iteration and development speed\r\n- You want to minimize native code maintenance\r\n- You're prototyping or building an MVP\r\n- Cross-platform consistency is a priority\r\n\r\n**Consider bare React Native when:**\r\n\r\n- You have sophisticated native requirements\r\n- Bundle size and raw performance are critical\r\n- You have lots of native development experience\r\n- You require highly specific third-party libraries that do not have Expo support\r\n- You want maximum control over the entire stack\r\n\r\n## The Middle Ground: Custom Development Builds\r\n\r\nIt's worth noting that Expo's architecture supports a hybrid approach. You can use custom development builds (prebuild workflow) to get the benefits of Expo's SDK and tooling while maintaining the flexibility to add any native code you need. This middle ground is becoming increasingly popular.\r\n\r\n## Final Thoughts\r\n\r\nAs it stands in 2025, Expo is a solid framework that has powered lots of successful apps and is flexible enough to add value to just about any React Native app. Though for some use cases, where there are more complex native concerns, Expo may not be a perfect fit.","content_text":"The React Native ecosystem has improved significantly over the years, and Expo has evolved from a beginner friendly wrapper into a robust mobile framework. Native developers face an important decision when starting a project: should you build your React Native app with Expo, or go the bare React Native route? Let's explore the advantages and concerns to help you make an informed choice.\nWhat is Expo?\n\nFor those new to the ecosystem, Expo is a framework and platform built around React Native that provides a set of tools and services to drastically simplify mobile app development. It offers a workflow that abstracts virtually all of the native code configuration and a bare workflow for those who need more control over native code directories.\nThe Advantages: Why Expo Shines in 2025\nRapid Development and Iteration\n\nThe strongest advantage of Expo is its ability to accelerate development. With Expo Go, developers can test apps on physical devices without complex build processes. The development experience with Expo Go is immediate, you write code, save, and see the changes almost instantly on your device.\n\nOver-the-air (OTA) updates through EAS (Expo Application Services) Update allow you to push JavaScript updates directly to users without having to go through the app store review process. For patches, bug fixes, and non-native changes, this is a game changer.\nEAS (Expo Application Services)\n\nEAS has matured into a comprehensive suite of cloud services that rival any CI/CD platform. EAS Build handles iOS and Android builds in the cloud. EAS Submit automates app store submissions, and EAS Update manages over the air deployments.\n\nFor teams without dedicated DevOps resources, EAS is simple enough to manage the build and submission processes.\nRich SDK and Native Modules\n\nThe expo-modules API provides tested and documented modules for camera access, location services, push notifications, and dozens of other features. These modules work consistently across platforms and are maintained by the Expo team. There is also the option to write your own custom native modules if you need to.\nSuperior Developer Experience\n\nThe tooling ecosystem around Expo is excellent. Expo CLI provides intuitive commands, helpful error messages, and streamlined workflows. The documentation is comprehensive and regularly updated. TypeScript support is first-class, with excellent type definitions across the entire SDK.\n\nMetro bundler configuration, app config management, and environment variable handling are all significantly simpler with Expo's opinionated approach.\nCross-Platform Consistency\n\nExpo's modules are designed with cross-platform consistency in mind. Behavioral differences between iOS and Android are minimized, and APIs are designed to feel natural on both platforms. This reduces the \"write once, debug everywhere\" problem that sometimes occurs in React Native development.\nThe Concerns: Where Expo Falls Short\nCost Considerations\n\nWhile Expo's open source tools are free, EAS services operate on a pricing model that scales with usage. For hobbyists and small projects, the free tier is a decent offering. However, for larger teams or apps with frequent builds, costs can accumulate quickly. Build minutes, submission operations, and bandwidth for updates all factor into the pricing for EAS.\nNative Module Limitations\n\nDespite constant improvements, there are still scenarios where Expo's abstraction layer gets in the way. Some third-party libraries with native dependencies don't support Expo out of the box. While you can use custom development builds or config plugins to integrate most libraries, this can add lot of complexity and convolute what was a simplified workflow. \n\nHighly specialized apps with unique native requirements may find themselves fighting against Expo's conventions rather than benefiting from them.\nDependency on Expo's Ecosystem\n\nChoosing Expo means buying into their ecosystem and release cycle. You're dependent on Expo's team to maintain modules, update dependencies, and support new React Native versions. While they have a strong track record, there's always some risk when tying your app's foundation to a third-party framework.\n\nSDK upgrades can sometimes be breaking, requiring code changes across your application. While Expo provides upgrade helpers and documentation, migrating between major versions still requires testing and validation.\nLearning Curve for Native Development\n\nExpo's abstraction layer can be a double-edged sword. Expo lowers the barrier to entry, but developers who exclusively use Expo may find themselves lacking the deep native knowledge needed to solve issues when they arise at the native level. Debugging can be challenging without understanding of Xcode, Android Studio, and native build systems.\n\nTeams may find themselves stuck when facing edge cases that require native-level debugging or customization.\nOTA Update Limitations\n\nWhile OTA updates are powerful, they have important constraints. You can only update JavaScript code and assets while native code changes will require a full app store submission. Large JavaScript bundles can also make OTA updates slow on poor network connections.\n\nThere are also compliance considerations. Some app store review processes scrutinize apps that update their code outside of the review process, particularly in regulated industries.\nWhat's right for your project?\n\nExpo is an excellent choice when:\n\n\nYou're building a standard app without exotic native requirements\nYour team values rapid iteration and development speed\nYou want to minimize native code maintenance\nYou're prototyping or building an MVP\nCross-platform consistency is a priority\n\n\nConsider bare React Native when:\n\n\nYou have sophisticated native requirements\nBundle size and raw performance are critical\nYou have lots of native development experience\nYou require highly specific third-party libraries that do not have Expo support\nYou want maximum control over the entire stack\n\nThe Middle Ground: Custom Development Builds\n\nIt's worth noting that Expo's architecture supports a hybrid approach. You can use custom development builds (prebuild workflow) to get the benefits of Expo's SDK and tooling while maintaining the flexibility to add any native code you need. This middle ground is becoming increasingly popular.\nFinal Thoughts\n\nAs it stands in 2025, Expo is a solid framework that has powered lots of successful apps and is flexible enough to add value to just about any React Native app. Though for some use cases, where there are more complex native concerns, Expo may not be a perfect fit.\n","summary":"The React Native ecosystem has improved significantly over the years, and Expo has evolved from a beginner friendly wrapper into a robust mobile framework. Native developers face an important decision when starting a project: should you build your React Native app with Expo, or go the bare React Native route? Let's explore the advantages and concerns to help you make an informed choice.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/1036/view-grounds-buildings-lakefront-Worlds-Columbian-Exposition-1892.webp","date_published":"2025-11-11T09:00:00-05:00","data_modified":"2025-11-03T16:15:54-05:00","author":{"name":"Jack Rosa","url":"https://hashrocket.com/team/jackrosa","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/112/headshot.jpg"},"tags":["Mobile","React Native"]},{"id":"https://hashrocket.com/blog/posts/cast-iphone-screen-to-mac","url":"https://hashrocket.com/blog/posts/cast-iphone-screen-to-mac","title":"Cast/Share your iPhone/iPad screen to Mac","content_html":"If you are pairing remotely on a mobile web project or doing a presentation that includes a mobile demo it is often helpful to share your iOS screen on your Mac.\n\nRecently, we have been working on a project that uses ApplePay on the web which proved difficult to test on a desktop computer, and we wanted to show how it worked on an iPhone.\r\n\r\nThere are quite a few software products that can help you achieve this goal, but many of them cost money or are unreliable. In this post I will share with you some solutions I have used successfully to share my mobile device's screen. I’m not going to cover all the solutions that exist out there, and ultimately there are no right or wrong answers - it is whatever works for your use case.\r\n\r\n## Reflector - Cost: $14.99\r\n[Reflector](https://www.airsquirrels.com/reflector) is a software solution by Air Squirrels that turns your Mac into an AirPlay/ChromeCast device that you can then mirror your phone into.\r\n\r\nIt supports multiple device screen mirroring and can even record your screen on multiple devices at once. Pairing is super easy and uses common protocols for sharing a screen such as AirPlay, which is built into all iOS devices. You can even use Android devices using ChromeCast. \r\n\r\n![Imgur](https://i.imgur.com/jJDnmy7.jpg)\r\n\r\nOut of all the streaming solutions I used, this one is the best at what it does.\r\n\r\nCons:\r\n\r\n* Although this solution works great most of the time, I did have errors connecting a few times in the past. But, those are relatively rare and sometimes depend on your network setup (you have to be on the same WiFi your Mac is on with your iPhone). \r\n* Updates are not free, and there appears to be a new version every year or so with no earth shattering changes in functionality. Your old version will probably work until macOS gets updated or something breaks and then you have to spend another $15.\r\n\r\n![Imgur](https://i.imgur.com/79fHOfd.png)\r\n\r\n## Quick Time - Cost: FREE\r\nQuickTime comes built-in with macOS and gives you this functionality for free. To get started, you will need to connect your iOS device to your computer via [Lightning to USB cable](https://www.apple.com/shop/product/MQUE2AM/A/lightning-to-usb-cable-1-m) and follow these steps:\r\n\r\n1. Open QuickTime\r\n2. Click File -\u003e New Movie Recording\r\n\r\n![Imgur](https://i.imgur.com/hDBXWF2.png)\r\n\r\n3. In the window that opens, click the tiny down facing arrow next to the record button and select your iOS device under the Camera section (you can also select your device as the Microphone to record the sounds from the device):\r\n\r\n![Imgur](https://i.imgur.com/dhc02aj.png)\r\n\r\nThat’s it. You can now share your screen via VNC or any other screen sharing software you use, and your screen will include your phone. Or, you can record a video of your screen to share with clients.\r\n\r\nThe QuickTime solution is usually my preferred option since it is installed on all Macs, and it’s pretty straight forward. The quality also seems much better than the streaming solution.\r\n\r\nCons:\r\n\r\n* You must have a Lightning to USB cable lying around to use this solution\r\n  * If you have a newer MacBooks you would need a Lightning to USB-C or an adapter from USB to USB-C\r\n* You are tethered to your computer while casting\r\n\r\n## Zoom - FREE 40-minute sessions, Subscription based\r\n[Zoom](https://zoom.us/) is becoming my favorite video conferencing solution, despite being proprietary and subscription based. The video and audio quality compared to any other solution I’ve used is just phenomenal. \r\n\r\nThe free version will get you pretty far; it should suffice for most business related calls or debugging sessions.\r\n\r\nTo start, open a video call and press the Share Screen button:\r\n\r\n![Imgur](https://i.imgur.com/HVEIlI3.png)\r\n\r\nThen in the menu select iPhone//iPad via AirPlay or iPhone//iPad via Cable:\r\n\r\n![Imgur](https://i.imgur.com/rXwsGkO.png)\r\n\r\nThat’s it.\r\n\r\n![Imgur](https://i.imgur.com/jiRvorc.png)\r\n\r\nThis solution was best when we needed our client to show us what she was experiencing when testing our solution on her mobile phone.\r\n\r\nCons:\r\n\r\n* Privacy. I am usually reasonably suspicious of anything that can record my screen and transmit it to others. Since this is a third party solution they could be recording the video and storing it on their servers which could include information such as your phone password/credit card information or basically anything you type on your phone. Their servers could be compromised in a data breach, or they could be sharing your data with third parties without your knowledge.\r\n* It’s not completely free, and the 40-minute limit means it would not work for all-day remote pairing sessions.\r\n\r\n## Conclusion\r\nCasting your iPhone screen to a Mac can be done in a variety of different ways and it is fairly easy to do. It can allow you to pair on mobile projects or help debug an issue with a client on call. Depending on your needs and your budget, you should do your research and make the best decision, but be sure to try the free solutions first.","content_text":"If you are pairing remotely on a mobile web project or doing a presentation that includes a mobile demo it is often helpful to share your iOS screen on your Mac.\n\nRecently, we have been working on a project that uses ApplePay on the web which proved difficult to test on a desktop computer, and we wanted to show how it worked on an iPhone.\n\nThere are quite a few software products that can help you achieve this goal, but many of them cost money or are unreliable. In this post I will share with you some solutions I have used successfully to share my mobile device's screen. I’m not going to cover all the solutions that exist out there, and ultimately there are no right or wrong answers - it is whatever works for your use case.\nReflector - Cost: $14.99\n\nReflector is a software solution by Air Squirrels that turns your Mac into an AirPlay/ChromeCast device that you can then mirror your phone into.\n\nIt supports multiple device screen mirroring and can even record your screen on multiple devices at once. Pairing is super easy and uses common protocols for sharing a screen such as AirPlay, which is built into all iOS devices. You can even use Android devices using ChromeCast. \n\n\n\nOut of all the streaming solutions I used, this one is the best at what it does.\n\nCons:\n\n\nAlthough this solution works great most of the time, I did have errors connecting a few times in the past. But, those are relatively rare and sometimes depend on your network setup (you have to be on the same WiFi your Mac is on with your iPhone). \nUpdates are not free, and there appears to be a new version every year or so with no earth shattering changes in functionality. Your old version will probably work until macOS gets updated or something breaks and then you have to spend another $15.\n\n\n\nQuick Time - Cost: FREE\n\nQuickTime comes built-in with macOS and gives you this functionality for free. To get started, you will need to connect your iOS device to your computer via Lightning to USB cable and follow these steps:\n\n\nOpen QuickTime\nClick File -\u0026gt; New Movie Recording\n\n\n\n\n\nIn the window that opens, click the tiny down facing arrow next to the record button and select your iOS device under the Camera section (you can also select your device as the Microphone to record the sounds from the device):\n\n\n\n\nThat’s it. You can now share your screen via VNC or any other screen sharing software you use, and your screen will include your phone. Or, you can record a video of your screen to share with clients.\n\nThe QuickTime solution is usually my preferred option since it is installed on all Macs, and it’s pretty straight forward. The quality also seems much better than the streaming solution.\n\nCons:\n\n\nYou must have a Lightning to USB cable lying around to use this solution\n\n\nIf you have a newer MacBooks you would need a Lightning to USB-C or an adapter from USB to USB-C\n\nYou are tethered to your computer while casting\n\nZoom - FREE 40-minute sessions, Subscription based\n\nZoom is becoming my favorite video conferencing solution, despite being proprietary and subscription based. The video and audio quality compared to any other solution I’ve used is just phenomenal. \n\nThe free version will get you pretty far; it should suffice for most business related calls or debugging sessions.\n\nTo start, open a video call and press the Share Screen button:\n\n\n\nThen in the menu select iPhone//iPad via AirPlay or iPhone//iPad via Cable:\n\n\n\nThat’s it.\n\n\n\nThis solution was best when we needed our client to show us what she was experiencing when testing our solution on her mobile phone.\n\nCons:\n\n\nPrivacy. I am usually reasonably suspicious of anything that can record my screen and transmit it to others. Since this is a third party solution they could be recording the video and storing it on their servers which could include information such as your phone password/credit card information or basically anything you type on your phone. Their servers could be compromised in a data breach, or they could be sharing your data with third parties without your knowledge.\nIt’s not completely free, and the 40-minute limit means it would not work for all-day remote pairing sessions.\n\nConclusion\n\nCasting your iPhone screen to a Mac can be done in a variety of different ways and it is fairly easy to do. It can allow you to pair on mobile projects or help debug an issue with a client on call. Depending on your needs and your budget, you should do your research and make the best decision, but be sure to try the free solutions first.\n","summary":"If you are pairing remotely on a mobile web project or doing a presentation that includes a mobile demo it is often helpful to share your iOS screen on your Mac.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/469/cast_iphone.jpg","date_published":"2019-03-12T09:00:00-04:00","data_modified":"2019-03-12T10:11:12-04:00","author":{"name":"Dorian Karter","url":"https://hashrocket.com/team/dorian-karter","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/91/dorian-karter.jpg"},"tags":["Mobile","pairing","Debugging"]},{"id":"https://hashrocket.com/blog/posts/tips-and-tricks-from-integrating-react-native-with-existing-native-apps","url":"https://hashrocket.com/blog/posts/tips-and-tricks-from-integrating-react-native-with-existing-native-apps","title":"Tips and Tricks from Integrating React Native with Existing Mobile Apps","content_html":"A lot of clients come to Hashrocket with an existing mobile app and they expect us to deliver new features as soon as possible. With an easy integration, native performance, support for the main platforms and great development experience, React Native has proved to be the right choice for maintaining existing mobile apps.\r\n\r\nThis blog post describes some of the tips and tricks that we face when we integrate React Native with existing apps. The examples are mostly for iOS but they apply for Android on most of the cases.\n\n## Introducing RCTRootView\r\n\r\nThe integration between React Native and native code is straightforward. For iOS, React Native exposes a *UIView* subclass called `RCTRootView` that can be embedded in any part of your app. Here is a simple example that adds a *RCTRootView* as a subview of a *UIViewController*'s view:\r\n\r\n```objc\r\n-(void)viewDidLoad {\r\n  \r\n  ...\r\n  \r\n  NSURL *jsUrl = [NSURL URLWithString:@\"http://localhost:8081/index.ios.bundle?platform=ios\"];\r\n  \r\n  self.reactView = [[RCTRootView alloc] \r\n      initWithBundleURL:jsUrl\r\n      moduleName:@\"SampleApp\"\r\n      initialProperties:nil\r\n      launchOptions:nil];\r\n                                            \r\n  [self.view addSubview:self.reactView];\r\n}\r\n```\r\n\r\nTo read more about setting up the integration with your existing app, just follow the official [docs](https://facebook.github.io/react-native/docs/integration-with-existing-apps.html).\r\n\r\nNow we need to learn how we can send messages between native code and React Native and vice versa.\r\n\r\n## Sending messages from native code to React\r\n\r\nThere are basically two ways to send messages from native code to a React view: using properties or event dispatcher.\r\n\r\n### Using properties\r\n\r\nReact components talk to each other through properties (props) and you can use the same approach to send messages from native code to a react view. All *RCTRootView* have a property called `appProperties` where you can set a dictionary that can be used on the React component: \r\n\r\n```objc\r\nself.reactview.appProperties = @{@\"status\": @\"success\"};\r\n```\r\n\r\nEvery time the *appProperties* is changed React will re-render the root component:\r\n\r\n```javascript\r\nrender() {\r\n  return \u003cText\u003e{this.props.status}\u003c/Text\u003e\r\n}\r\n```\r\n\r\nBut be careful with boolean values. Let say you have a pull-to-refresh feature on a regular *UITableView* and one of the cells is rendered by React. So the first time you pull to refresh the list, the React cell should also refresh and you set a `reload` prop to `YES`:\r\n\r\n```objc\r\n-(void)onRefresh {\r\n  self.reactView.appProperties = @{@\"reload\": @YES};\r\n}\r\n```\r\n\r\nAnd on the React component you check if the `reload` prop is set when the component receives new props and reload the data:\r\n\r\n```javascript\r\ncomponentWillReceiveProps(nextProps) {\r\n  if (nextProps.reload) {\r\n    this._reloadData();\r\n  }\r\n}\r\n\r\n```\r\n\r\nSo the first time this happens it works fine, but the second time you pull to refresh the list nothing is reloaded. This happens because you are setting the same boolean value for the same prop `@{@\"reload\": @YES}`. React will not propagate the props if they haven't changed. So one way to solve this issue is just setting a timestamp for the prop instead of a boolean value: \r\n\r\n```objc\r\n-(void)onRefresh {\r\n  self.reactView.appProperties = @{\r\n    @\"reload\": @(CFAbsoluteTimeGetCurrent())\r\n  };\r\n}\r\n\r\n``` \r\n\r\n\r\n### Using Event Dispatcher\r\n\r\nThe other way to communicate to a React component is using the event dispatcher. All bridges from a *RCTRootView* have a reference to a global event dispatcher where you can dispatch events:\r\n \r\n```objc\r\n[self.reactView.bridge.eventDispatcher \r\n             sendDeviceEventWithName:@\"statusDidChange\"\r\n             body:@{@\"status\": status}];\r\n```\r\n\r\nAnd on your react component just add a listener to the event:\r\n\r\n```javascript\r\ncomponentWillMount() {\r\n  this._listener = DeviceEventEmitter.addListener(\"statusDidChange\", (event) =\u003e {\r\n    console.log(event.status);\r\n  });\r\n}\r\n```\r\n\r\nAnd don't forget to remove the listener when the component unmounts:\r\n\r\n```javascript\r\ncomponentWillUnmount() {\r\n  this._listener.remove();\r\n}\r\n```\r\n\r\nYou could also use the [Subscribable](https://github.com/facebook/react-native/blob/master/Libraries/Components/Subscribable.js) mixin that automatically removes the listeners when the component will unmount.\r\n\r\n*It looks like `sendDeviceEventWithName` is deprecated now in favor of a more generic method called `sendEvent`.\r\n\r\n## Sending messages from React to native code\r\n\r\nThe `RCTRootView` has no interface to receive messages from the React component but the way to achieve this is writing native modules. \r\n\r\nA native module is a class that defines methods that can be exposed to the javascript code. They are singletons, meaning they are shared between multiple React view instances. On the example below we can write a generic native module that uses `NSNotificationCenter` to broadcast messages from React to the rest of the native app:\r\n\r\n\r\n```objc\r\n@interface NotificationsModule : NSObject\u003cRCTBridgeModule\u003e\r\n@end\r\n\r\n@implementation NotificationsModule\r\n\r\nRCT_EXPORT_MODULE();\r\n\r\nRCT_EXPORT_METHOD(sendNotification:(NSString*)notification params:(NSDictionary*)params) {\r\n  [[NSNotificationCenter defaultCenter] \r\n      postNotificationName:event \r\n      object:nil \r\n      userInfo:params];\r\n}\r\n\r\n@end\r\n```\r\n\r\nAnd on your React component you can just call the same method that was exported:\r\n\r\n\r\n```javascript\r\nimport { NativeModules } from 'react-native';\r\nconst NotificationsModule = NativeModules.NotificationsModule;\r\n\r\nrender() {\r\n  return \u003cTouchableOpacity onPress={this._onPress} /\u003e\r\n}\r\n\r\n_onPress() {\r\n  const params = { rootTag: this.props.rootTag, userId: this.props.userId };\r\n  NotificationsModule.sendNotification(\"openUserScreen\", params);\r\n}\r\n```\r\n\r\nNote that we are setting the prop `rootTag` on the notification params. All React root components have a property called *rootTag* that identifies the React View *RCTRootView*. In some cases you only need to handle notifications from a specific *RCTRootView* and comparing the rootTag is the way to do this. In order to access the *rootTag* from the *RCTRootView* you will have to include the category `UIView+React.h` that will expose the method `reactTag`:\r\n\r\n```objc\r\n#import \"UIView+React.h\"\r\n\r\n-(void)viewDidLoad {\r\n  [[NSNotificationCenter defaultCenter] \r\n      addObserver:self \r\n      selector:@selector(didReceiveOpenUserNotification) \r\n      name:@\"openUserScreen\"\r\n      object:nil];\r\n}\r\n\r\n-(void)didReceiveOpenUserNotification:(NSNotification *)notification {\r\n  NSDictionary *params = notification.userInfo;\r\n  if ([self.reactView.reactTag isEqualToNumber:params.rootTag]) {\r\n    [self openUserController:params.userId];\r\n  }\r\n}\r\n\r\n```\r\n\r\n\r\n## Custom native views as components\r\n\r\nAnother nice thing is that you can bring to React Native any existing custom UIView that you wrote. You just need to create a new class that inherits from `RCTViewManager`, then implement the `view` method to return the instance of your custom view and then expose the properties you want to be available on the React component:\r\n\r\n```objc\r\n@interface GoCoderManager : RCTViewManager\r\n@end\r\n\r\n@implementation GoCoderManager\r\n\r\nRCT_EXPORT_MODULE(GoCoder)\r\n\r\n-(UIView *)view {\r\n  return [GoCoderView new];\r\n}\r\n\r\nRCT_EXPORT_VIEW_PROPERTY(initialCamera, NSString);\r\nRCT_EXPORT_VIEW_PROPERTY(onImageCaptured, RCTBubblingEventBlock);\r\n\r\n@end\r\n```\r\n\r\nNote that the second property exported in the example is a type of `RCTBubblingEventBlock`. This is the way you can send events from native custom views to the parent component that is using it.\r\n\r\nTo use this custom component inside React:\r\n\r\n```javascript\r\nimport {\r\n  requireNativeComponent,\r\n} from 'react-native';\r\n\r\nconst GoCoder = requireNativeComponent('GoCoder', null);\r\n\r\nclass ParentComponent extends Component {\r\n  render() {\r\n    return (\r\n      \u003cView\u003e\r\n        \u003cGoCoder initialCamera=\"back\" onImageCaptured={() =\u003e {\r\n            alert(\"Image captured!\")\r\n        }} /\u003e\r\n      \u003c/View\u003e\r\n    );\r\n  }\r\n}\r\n```\r\n\r\nTo see more about this integration read the official [docs](https://facebook.github.io/react-native/docs/native-components-ios.html).\r\n\r\n\r\n## Touchable React views inside scrollable native views\r\n\r\nLet's say you have a *UITableView* filling the whole screen and one of the cells is a React Native view. You may see some strange behaviors now. When you are scrolling down the table and the first touch happens inside the React view, it will fire that event as a regular touch event to the React view causing your app to go to another screen instead of scrolling down the page.\r\n\r\nOne way to fix this issue is implementing the method `scrollViewDidScroll` from UIScrollViewDelegate and call `cancelTouches` on the React View:\r\n\r\n```objc\r\n- (void)scrollViewDidScroll:(UIScrollView *)scrollView {\r\n  [self.reactView cancelTouches];\r\n}\r\n```\r\n\r\n\r\n## Component Size\r\n\r\nYou don't need to specify the width and height for your components. React Native uses flexbox to style the views and calculates everything for you. But sometimes you need to know the exact height of a component. One example is when you have a `UITableView` and one of the cells is a React view. On iOS you have to specify the height of each cell so you need to know the height of the component. To get this data you will have to set `onLayout` prop on your component:\r\n\r\n```javascript\r\nrender() {\r\n  return (\r\n    \u003cView onLayout={this._onLayout)}\u003e\r\n      ...\r\n    \u003c/View\u003e\r\n  );\r\n}\r\n\r\n_onLayout(event) {\r\n  const { height } = event.nativeEvent.layout;\r\n  const params = { rootTag: this.props.rootTag, height };\r\n  NotificationsModule.sendNotification(\"componentHeightDidChange\", params);\r\n}\r\n```\r\n\r\n\r\n## Detecting orientation changes\r\n\r\nYou can detect the orientation of your device using the `onLayout` prop that was mentioned above on the root component of your app:\r\n\r\n```javascript\r\nrender() {\r\n  return (\r\n    \u003cView onLayout={this._onLayout}\u003e\r\n      ...\r\n    \u003c/View\u003e\r\n  );\r\n}\r\n\r\n_onLayout(event) {\r\n  const { width, height } = event.nativeEvent.layout;\r\n  const orientation = width \u003e height ? 'landscape' : 'portrait';\r\n  this.setState({orientation});\r\n}\r\n```\r\n\r\n\r\n## Relative units\r\n\r\nYou should not be writing conditions on your code to support all the different available screen sizes.\r\nOne way to avoid this conditions is using relative units based on the device's width.\r\n\r\nThere is this library [react-native-extended-stylesheet](https://github.com/vitalets/react-native-extended-stylesheet) that adds extra features to the default Stylesheet class, including `rem` support. On the example below the rem is set to the device width divided by 32. We've chosen 32 because it makes 1rem on the iPhone 5 to be equivalent to 10 pixels (base-10 number system is always easy for us).\r\n\r\n```javascript\r\nEStyleSheet.build({\r\n  rem: Dimensions.get('window').width / 32,\r\n});\r\n\r\nconst styles = EStyleSheet.create({\r\n  text: {\r\n    fontSize: '1.4rem'\r\n  }\r\n});\r\n\r\n```\r\n\r\nIt's worth mentioning that this approach may not work properly if your component needs to support landscape and portrait mode.\r\n\r\n\r\n## Globally update default component props \r\n\r\nOn your `index.ios.js` you can get any component class and override the default prop.\r\nOne example that we had to set was the property `allowFontScaling` to false because just few screens were supported.\r\n\r\n```javascript\r\nimport { Text } from 'react-native';\r\n\r\nText.defaultProps.allowFontScaling = false;\r\n```\r\n\r\n## NavigationExperimental\r\n\r\nNavigationExperimental is a new way to write navigation logic that decouples the state from the component. The NavigationExperimental has a [RFC](https://github.com/ericvicenti/navigation-rfc) that changed a lot over the past months and depending on the version you started using it may have changed completely. Our advice is to avoid using experimental features until they are mature enough or try to update React Native every time a new release comes up (every 2 weeks) so you are not that behind the latest changes on the specification.\r\n\r\n## JS errors in release builds\r\n\r\nDifferent from development builds that show a big red error screen, your app will crash in production if a JS error happens. The good thing is that if you are using a service to track errors like Crashlytics or NewRelic, you will get a nice error message and you will be able to identify on your JS code what caused the error.\r\n\r\n## Overflow hidden/visible\r\n\r\nThere is a difference on how iOS and Android deal with the overflow property. The `overflow: hidden` on Android doesn't look like it has any effect. So our advice is to try to avoid using it until this is fully supported.\r\n\r\n## More to cover\r\n\r\nThere are a lot more to talk about the React and React Native ecosystem that we want to cover on other blog posts:\r\n\r\n* testing: jest, snapshot tests, shallow rendering\r\n* redux: middlewares\r\n* graphql, relay and apollo client\r\n* fastlane integration\r\n\r\n","content_text":"A lot of clients come to Hashrocket with an existing mobile app and they expect us to deliver new features as soon as possible. With an easy integration, native performance, support for the main platforms and great development experience, React Native has proved to be the right choice for maintaining existing mobile apps.\n\nThis blog post describes some of the tips and tricks that we face when we integrate React Native with existing apps. The examples are mostly for iOS but they apply for Android on most of the cases.\nIntroducing RCTRootView\n\nThe integration between React Native and native code is straightforward. For iOS, React Native exposes a UIView subclass called RCTRootView that can be embedded in any part of your app. Here is a simple example that adds a RCTRootView as a subview of a UIViewController's view:\n-(void)viewDidLoad {\n\n  ...\n\n  NSURL *jsUrl = [NSURL URLWithString:@\"http://localhost:8081/index.ios.bundle?platform=ios\"];\n\n  self.reactView = [[RCTRootView alloc] \n      initWithBundleURL:jsUrl\n      moduleName:@\"SampleApp\"\n      initialProperties:nil\n      launchOptions:nil];\n\n  [self.view addSubview:self.reactView];\n}\n\nTo read more about setting up the integration with your existing app, just follow the official docs.\n\nNow we need to learn how we can send messages between native code and React Native and vice versa.\nSending messages from native code to React\n\nThere are basically two ways to send messages from native code to a React view: using properties or event dispatcher.\nUsing properties\n\nReact components talk to each other through properties (props) and you can use the same approach to send messages from native code to a react view. All RCTRootView have a property called appProperties where you can set a dictionary that can be used on the React component: \nself.reactview.appProperties = @{@\"status\": @\"success\"};\n\nEvery time the appProperties is changed React will re-render the root component:\nrender() {\n  return \u0026lt;Text\u0026gt;{this.props.status}\u0026lt;/Text\u0026gt;\n}\n\nBut be careful with boolean values. Let say you have a pull-to-refresh feature on a regular UITableView and one of the cells is rendered by React. So the first time you pull to refresh the list, the React cell should also refresh and you set a reload prop to YES:\n-(void)onRefresh {\n  self.reactView.appProperties = @{@\"reload\": @YES};\n}\n\nAnd on the React component you check if the reload prop is set when the component receives new props and reload the data:\ncomponentWillReceiveProps(nextProps) {\n  if (nextProps.reload) {\n    this._reloadData();\n  }\n}\n\n\nSo the first time this happens it works fine, but the second time you pull to refresh the list nothing is reloaded. This happens because you are setting the same boolean value for the same prop @{@\"reload\": @YES}. React will not propagate the props if they haven't changed. So one way to solve this issue is just setting a timestamp for the prop instead of a boolean value: \n-(void)onRefresh {\n  self.reactView.appProperties = @{\n    @\"reload\": @(CFAbsoluteTimeGetCurrent())\n  };\n}\n\nUsing Event Dispatcher\n\nThe other way to communicate to a React component is using the event dispatcher. All bridges from a RCTRootView have a reference to a global event dispatcher where you can dispatch events:\n[self.reactView.bridge.eventDispatcher \n             sendDeviceEventWithName:@\"statusDidChange\"\n             body:@{@\"status\": status}];\n\nAnd on your react component just add a listener to the event:\ncomponentWillMount() {\n  this._listener = DeviceEventEmitter.addListener(\"statusDidChange\", (event) =\u0026gt; {\n    console.log(event.status);\n  });\n}\n\nAnd don't forget to remove the listener when the component unmounts:\ncomponentWillUnmount() {\n  this._listener.remove();\n}\n\nYou could also use the Subscribable mixin that automatically removes the listeners when the component will unmount.\n\n*It looks like sendDeviceEventWithName is deprecated now in favor of a more generic method called sendEvent.\nSending messages from React to native code\n\nThe RCTRootView has no interface to receive messages from the React component but the way to achieve this is writing native modules. \n\nA native module is a class that defines methods that can be exposed to the javascript code. They are singletons, meaning they are shared between multiple React view instances. On the example below we can write a generic native module that uses NSNotificationCenter to broadcast messages from React to the rest of the native app:\n@interface NotificationsModule : NSObject\u0026lt;RCTBridgeModule\u0026gt;\n@end\n\n@implementation NotificationsModule\n\nRCT_EXPORT_MODULE();\n\nRCT_EXPORT_METHOD(sendNotification:(NSString*)notification params:(NSDictionary*)params) {\n  [[NSNotificationCenter defaultCenter] \n      postNotificationName:event \n      object:nil \n      userInfo:params];\n}\n\n@end\n\nAnd on your React component you can just call the same method that was exported:\nimport { NativeModules } from 'react-native';\nconst NotificationsModule = NativeModules.NotificationsModule;\n\nrender() {\n  return \u0026lt;TouchableOpacity onPress={this._onPress} /\u0026gt;\n}\n\n_onPress() {\n  const params = { rootTag: this.props.rootTag, userId: this.props.userId };\n  NotificationsModule.sendNotification(\"openUserScreen\", params);\n}\n\nNote that we are setting the prop rootTag on the notification params. All React root components have a property called rootTag that identifies the React View RCTRootView. In some cases you only need to handle notifications from a specific RCTRootView and comparing the rootTag is the way to do this. In order to access the rootTag from the RCTRootView you will have to include the category UIView+React.h that will expose the method reactTag:\n#import \"UIView+React.h\"\n\n-(void)viewDidLoad {\n  [[NSNotificationCenter defaultCenter] \n      addObserver:self \n      selector:@selector(didReceiveOpenUserNotification) \n      name:@\"openUserScreen\"\n      object:nil];\n}\n\n-(void)didReceiveOpenUserNotification:(NSNotification *)notification {\n  NSDictionary *params = notification.userInfo;\n  if ([self.reactView.reactTag isEqualToNumber:params.rootTag]) {\n    [self openUserController:params.userId];\n  }\n}\n\nCustom native views as components\n\nAnother nice thing is that you can bring to React Native any existing custom UIView that you wrote. You just need to create a new class that inherits from RCTViewManager, then implement the view method to return the instance of your custom view and then expose the properties you want to be available on the React component:\n@interface GoCoderManager : RCTViewManager\n@end\n\n@implementation GoCoderManager\n\nRCT_EXPORT_MODULE(GoCoder)\n\n-(UIView *)view {\n  return [GoCoderView new];\n}\n\nRCT_EXPORT_VIEW_PROPERTY(initialCamera, NSString);\nRCT_EXPORT_VIEW_PROPERTY(onImageCaptured, RCTBubblingEventBlock);\n\n@end\n\nNote that the second property exported in the example is a type of RCTBubblingEventBlock. This is the way you can send events from native custom views to the parent component that is using it.\n\nTo use this custom component inside React:\nimport {\n  requireNativeComponent,\n} from 'react-native';\n\nconst GoCoder = requireNativeComponent('GoCoder', null);\n\nclass ParentComponent extends Component {\n  render() {\n    return (\n      \u0026lt;View\u0026gt;\n        \u0026lt;GoCoder initialCamera=\"back\" onImageCaptured={() =\u0026gt; {\n            alert(\"Image captured!\")\n        }} /\u0026gt;\n      \u0026lt;/View\u0026gt;\n    );\n  }\n}\n\nTo see more about this integration read the official docs.\nTouchable React views inside scrollable native views\n\nLet's say you have a UITableView filling the whole screen and one of the cells is a React Native view. You may see some strange behaviors now. When you are scrolling down the table and the first touch happens inside the React view, it will fire that event as a regular touch event to the React view causing your app to go to another screen instead of scrolling down the page.\n\nOne way to fix this issue is implementing the method scrollViewDidScroll from UIScrollViewDelegate and call cancelTouches on the React View:\n- (void)scrollViewDidScroll:(UIScrollView *)scrollView {\n  [self.reactView cancelTouches];\n}\nComponent Size\n\nYou don't need to specify the width and height for your components. React Native uses flexbox to style the views and calculates everything for you. But sometimes you need to know the exact height of a component. One example is when you have a UITableView and one of the cells is a React view. On iOS you have to specify the height of each cell so you need to know the height of the component. To get this data you will have to set onLayout prop on your component:\nrender() {\n  return (\n    \u0026lt;View onLayout={this._onLayout)}\u0026gt;\n      ...\n    \u0026lt;/View\u0026gt;\n  );\n}\n\n_onLayout(event) {\n  const { height } = event.nativeEvent.layout;\n  const params = { rootTag: this.props.rootTag, height };\n  NotificationsModule.sendNotification(\"componentHeightDidChange\", params);\n}\nDetecting orientation changes\n\nYou can detect the orientation of your device using the onLayout prop that was mentioned above on the root component of your app:\nrender() {\n  return (\n    \u0026lt;View onLayout={this._onLayout}\u0026gt;\n      ...\n    \u0026lt;/View\u0026gt;\n  );\n}\n\n_onLayout(event) {\n  const { width, height } = event.nativeEvent.layout;\n  const orientation = width \u0026gt; height ? 'landscape' : 'portrait';\n  this.setState({orientation});\n}\nRelative units\n\nYou should not be writing conditions on your code to support all the different available screen sizes.\nOne way to avoid this conditions is using relative units based on the device's width.\n\nThere is this library react-native-extended-stylesheet that adds extra features to the default Stylesheet class, including rem support. On the example below the rem is set to the device width divided by 32. We've chosen 32 because it makes 1rem on the iPhone 5 to be equivalent to 10 pixels (base-10 number system is always easy for us).\nEStyleSheet.build({\n  rem: Dimensions.get('window').width / 32,\n});\n\nconst styles = EStyleSheet.create({\n  text: {\n    fontSize: '1.4rem'\n  }\n});\n\n\nIt's worth mentioning that this approach may not work properly if your component needs to support landscape and portrait mode.\nGlobally update default component props\n\nOn your index.ios.js you can get any component class and override the default prop.\nOne example that we had to set was the property allowFontScaling to false because just few screens were supported.\nimport { Text } from 'react-native';\n\nText.defaultProps.allowFontScaling = false;\nNavigationExperimental\n\nNavigationExperimental is a new way to write navigation logic that decouples the state from the component. The NavigationExperimental has a RFC that changed a lot over the past months and depending on the version you started using it may have changed completely. Our advice is to avoid using experimental features until they are mature enough or try to update React Native every time a new release comes up (every 2 weeks) so you are not that behind the latest changes on the specification.\nJS errors in release builds\n\nDifferent from development builds that show a big red error screen, your app will crash in production if a JS error happens. The good thing is that if you are using a service to track errors like Crashlytics or NewRelic, you will get a nice error message and you will be able to identify on your JS code what caused the error.\nOverflow hidden/visible\n\nThere is a difference on how iOS and Android deal with the overflow property. The overflow: hidden on Android doesn't look like it has any effect. So our advice is to try to avoid using it until this is fully supported.\nMore to cover\n\nThere are a lot more to talk about the React and React Native ecosystem that we want to cover on other blog posts:\n\n\ntesting: jest, snapshot tests, shallow rendering\nredux: middlewares\ngraphql, relay and apollo client\nfastlane integration\n\n","summary":"A lot of clients come to Hashrocket with an existing mobile app and they expect us to deliver new features as soon as possible. With an easy integration, native performance, support for the main platforms and great development experience, React Native has proved to be the right choice for maintaining existing mobile apps.\n\nThis blog post describes some of the tips and tricks that we face when we integrate React Native with existing apps. The examples are mostly for iOS but they apply for Android on most of the cases.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/314/A_nursery_for_unruly_young_stars.jpg","date_published":"2016-08-25T09:00:00-04:00","data_modified":"2025-10-10T15:11:46-04:00","author":{"name":"Gabriel Reis","url":"https://hashrocket.com/team/gabriel-reis","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/47/gabriel-reis.jpg"},"tags":["Mobile","React Native"]},{"id":"https://hashrocket.com/blog/posts/setting-up-your-mac-for-android-development","url":"https://hashrocket.com/blog/posts/setting-up-your-mac-for-android-development","title":"Setting up your Mac for Android Development","content_html":"Installing Android SDK is straightforward but a few tweaks can make your development environment much faster and better.\n\n# Installing\r\nDownload the Android SDK bundle from the official [Android Developers page](http://developer.android.com/sdk/index.html). This bundle includes the Android SDK, Eclipse and other useful tools. \r\n\r\nUnzip the downloaded file anywhere and run the Eclipse Application. \r\n\r\nThis should be enough but the emulator will be extremely slow. No worries, there are some additional packages you can install to solve this problem. \r\n\r\n# Hardware acceleration\r\n\r\nOn Eclipse, go to Window -\u003e Android SDK Manager\r\nCheck the option \"Intel X86 Atom System Image\":\r\n\r\n![Android SDK Manager](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/setup_android_env.png)\r\n\r\nYou also need to install the \"Intel x86 Emulator Accelerator (HAXM)\" but until the date of this post, an important Hotfix for OS X 10.9 has not been included into this package at Android SDK Manager. So go ahead and download this file from the [Intel's website](http://software.intel.com/en-us/articles/intel-hardware-accelerated-execution-manager).\r\n\r\nTo ensure Eclipse is running properly we will create a \"Hello World\" Android app but first go ahead and close and re-open Eclipse so make our new packages available to be used.\r\n\r\nFor this click on the button New Android Application:\r\n\r\n![New Android App](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app.png)\r\n\r\nProvide an Application Name, for test proposes we named ours \"Test\" and accept all default options for the new project.\r\n\r\n![New Android App](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app1.png)\r\n![New Android App](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app2.png)\r\n![New Android App](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app3.png)\r\n![New Android App](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app4.png)\r\n![New Android App](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app5.png)\r\n\r\nBefore you can run the app on the emulator you will need to create an Android Virtual Device Manager.\r\n\r\nGo to Window -\u003e Android Virtual Device Manager -\u003e New \r\n\r\nProvide a name for your device, select a Device and Target.\r\nTo enable the hardware acceleration, make sure to select \"Intel Atom (x86)\" as CPU/ABI and to check \"Use Host GPU\" and then click OK:\r\n\r\n![New AVD](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app6.png)\r\n\r\nTo run your example app go to Run -\u003e Run As -\u003e Android Application. \r\n\r\nYou should see the emulator like this:\r\n\r\n![Hello World](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/hello_world.png)\r\n\r\nLook at the console log for \"HAX is working and emulator runs in fast virt mode\", this is the proof that the accelerator is working properly:\r\n\r\n![Console](https://s3.amazonaws.com/hashrocket-blog-production/setting_up_mac_for_android_dev/new_android_app7.png)\r\n\r\n# Vim Integration\r\n\r\nThere are a few solutions to integrate Vim with Eclipse. We've chosen the plugin [Vrapper](http://vrapper.sourceforge.net/) and it's the easiest one to install.\r\nIf you are not familiar how to install a plugin in Eclipse, just go to Help -\u003e Install New Software. A new window will popup, then click on the \"Add...\" button. Give it a name, like \"Vrapper - Vim plugin\" and set the location to \"http://vrapper.sourceforge.net/update-site/stable\"\r\n\r\nNow choose the Vrapper plugin, the Java extension and the [Surround.vim](https://github.com/tpope/vim-surround) plugin:\r\n\r\n![Vrapper](https://s3.amazonaws.com/hashrocket-blog-production/vrapper-plugin.png)\r\n\r\nAnyways those are some small tweaks we've found helpful. Let us know if there are any other improvements you'd suggest. \r\n\r\nHappy coding! \r\n\r\n\r\n*Update: You should be using [Android Studio](https://developer.android.com/studio/index.html) to develop for Android. It has a much better support and integration with all libraries.","content_text":"Installing Android SDK is straightforward but a few tweaks can make your development environment much faster and better.\nInstalling\n\nDownload the Android SDK bundle from the official Android Developers page. This bundle includes the Android SDK, Eclipse and other useful tools. \n\nUnzip the downloaded file anywhere and run the Eclipse Application. \n\nThis should be enough but the emulator will be extremely slow. No worries, there are some additional packages you can install to solve this problem. \nHardware acceleration\n\nOn Eclipse, go to Window -\u0026gt; Android SDK Manager\nCheck the option \"Intel X86 Atom System Image\":\n\n\n\nYou also need to install the \"Intel x86 Emulator Accelerator (HAXM)\" but until the date of this post, an important Hotfix for OS X 10.9 has not been included into this package at Android SDK Manager. So go ahead and download this file from the Intel's website.\n\nTo ensure Eclipse is running properly we will create a \"Hello World\" Android app but first go ahead and close and re-open Eclipse so make our new packages available to be used.\n\nFor this click on the button New Android Application:\n\n\n\nProvide an Application Name, for test proposes we named ours \"Test\" and accept all default options for the new project.\n\n\n\n\n\n\n\nBefore you can run the app on the emulator you will need to create an Android Virtual Device Manager.\n\nGo to Window -\u0026gt; Android Virtual Device Manager -\u0026gt; New \n\nProvide a name for your device, select a Device and Target.\nTo enable the hardware acceleration, make sure to select \"Intel Atom (x86)\" as CPU/ABI and to check \"Use Host GPU\" and then click OK:\n\n\n\nTo run your example app go to Run -\u0026gt; Run As -\u0026gt; Android Application. \n\nYou should see the emulator like this:\n\n\n\nLook at the console log for \"HAX is working and emulator runs in fast virt mode\", this is the proof that the accelerator is working properly:\n\n\nVim Integration\n\nThere are a few solutions to integrate Vim with Eclipse. We've chosen the plugin Vrapper and it's the easiest one to install.\nIf you are not familiar how to install a plugin in Eclipse, just go to Help -\u0026gt; Install New Software. A new window will popup, then click on the \"Add...\" button. Give it a name, like \"Vrapper - Vim plugin\" and set the location to \"http://vrapper.sourceforge.net/update-site/stable\"\n\nNow choose the Vrapper plugin, the Java extension and the Surround.vim plugin:\n\n\n\nAnyways those are some small tweaks we've found helpful. Let us know if there are any other improvements you'd suggest. \n\nHappy coding! \n\n*Update: You should be using Android Studio to develop for Android. It has a much better support and integration with all libraries.\n","summary":"Installing Android SDK is straightforward but a few tweaks can make your development environment much faster and better.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/163/android4.png","date_published":"2014-03-03T09:00:00-05:00","data_modified":"2016-08-26T16:10:25-04:00","author":{"name":"Gabriel Reis","url":"https://hashrocket.com/team/gabriel-reis","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/47/gabriel-reis.jpg"},"tags":["Android","Mobile"]},{"id":"https://hashrocket.com/blog/posts/wedclock-a-mobile-app","url":"https://hashrocket.com/blog/posts/wedclock-a-mobile-app","title":"Wedclock - A mobile app","content_html":"At Hashrocket we are encouraged to continually learn new skills. A few months ago I decided to use some of my open source and contribution time to learn iOS development. \r\n\n\nAfter I shared my desire to build an iPhone app with my co-workers, ideas started to pop around the office. I didn't want something too complicated, it had to be something that I could start and finish in few weeks. Adam Lowe mentioned that he could remember his anniversary date but could never answer the question, \"How long have you been married?\". Solving his problem fit the time I had to build an app and that is how [Wedclock](http://www.wedclockapp.com) went from a joke to a real app.\r\n\r\n[Rye Mason](https://hashrocket.com/team/rye-mason) also deserves a big thank you for contributing a great design for the app.\r\n\r\n[Wedclock](http://www.wedclockapp.com/) is an mobile app that will help married couple to remember their anniversary and let you know at any time how long you've been married and how long until your next anniversary.\r\n\r\n![iOS app](http://s3.amazonaws.com/hashrocket-blog-production/wedclock/iphone.png)\r\n\r\nAs I've said before, it is a really simple app but I had a lot of fun writing it. It was during it's development that [Gabriel](http://hashrocket.com/blog/rocketeers/gabriel-reis) and I learned about some cool [libraries](http://hashrocket.com/blog/posts/using-auto-layout-for-ios), had the idea for a [new iOS library](http://hashrocket.com/blog/posts/introducing-constraintformatter), played with some [testing frameworks](http://hashrocket.com/blog/posts/setting-up-kiwi-as-your-ios-unit-testing-framework) and created a series of blog posts about [mobile](http://hashrocket.com/blog/categories/mobile).\r\n\r\nEven though there are lots of cool features to be added to [Wedclock](http://www.wedclockapp.com/), we decided to go further and learn some more about Android development as well.\r\n\r\nJust 3 days ago we released the [Android version of the app](https://play.google.com/store/apps/details?id=com.wedclockapp.wedclock).\r\n\r\n![android app](http://s3.amazonaws.com/hashrocket-blog-production/wedclock/android.png)\r\n\r\nAnd of course, we will keep talking about our experience with iOS and Android development in more detail in future blog posts.\r\n   \r\nStay tuned!","content_text":"At Hashrocket we are encouraged to continually learn new skills. A few months ago I decided to use some of my open source and contribution time to learn iOS development. \n\nAfter I shared my desire to build an iPhone app with my co-workers, ideas started to pop around the office. I didn't want something too complicated, it had to be something that I could start and finish in few weeks. Adam Lowe mentioned that he could remember his anniversary date but could never answer the question, \"How long have you been married?\". Solving his problem fit the time I had to build an app and that is how Wedclock went from a joke to a real app.\n\nRye Mason also deserves a big thank you for contributing a great design for the app.\n\nWedclock is an mobile app that will help married couple to remember their anniversary and let you know at any time how long you've been married and how long until your next anniversary.\n\n\n\nAs I've said before, it is a really simple app but I had a lot of fun writing it. It was during it's development that Gabriel and I learned about some cool libraries, had the idea for a new iOS library, played with some testing frameworks and created a series of blog posts about mobile.\n\nEven though there are lots of cool features to be added to Wedclock, we decided to go further and learn some more about Android development as well.\n\nJust 3 days ago we released the Android version of the app.\n\n\n\nAnd of course, we will keep talking about our experience with iOS and Android development in more detail in future blog posts.\n\nStay tuned!\n","summary":"At Hashrocket we are encouraged to continually learn new skills. A few months ago I decided to use some of my open source and contribution time to learn iOS development. \n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/168/bg.png","date_published":"2014-02-06T09:00:00-05:00","data_modified":"2016-08-25T12:03:25-04:00","author":{"name":"Thais Camilo","url":"https://hashrocket.com/team/thais-camilo","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/46/thais-camilo.jpg"},"tags":["iOS","Android","Mobile"]},{"id":"https://hashrocket.com/blog/posts/setting-up-kiwi-as-your-ios-unit-testing-framework","url":"https://hashrocket.com/blog/posts/setting-up-kiwi-as-your-ios-unit-testing-framework","title":"Setting up Kiwi as your iOS unit testing framework","content_html":"It is well known that we at Hashrocket are advocates for the testing culture. After years of working with Ruby and Rails we've tried all kinds of testing frameworks, and there's no question that we like RSpec.\n\nWe feel that testing iOS apps should be similar, and we've being trying out different testing frameworks. Among them is [Kiwi](https://github.com/allending/Kiwi/wiki) which has a [RSpec]-like syntax for Objective-C.\r\n\r\nIt was a nightmare to setup Kiwi 1.0 with Xcode 4. However, everything is much easier with [Kiwi 2.0](https://github.com/allending/Kiwi/wiki) and Xcode 5.\r\n\r\nYou will find extensive documentation about the subject at [Kiwi's wiki](https://github.com/allending/Kiwi/wiki), but we would like to show you a simpler approach. \r\n\r\n\r\n## Creating the project\r\n\r\nCreate a new empty Xcode 5 project. For testing propose our app will be called \"KiwiExample\". \r\n \r\nXcode 5 will create a target called \"KiwiExampleTests\" for unit testing using framework XCTest. It will also generate a test case file containing 1 test example. \r\n\r\nTo run the test go to \"Product\" -\u003e \"Test\" on Xcode menu or use the shortcut \"CMD+u\". \r\n\r\nIf everything is correct you will get a \"No implementation\" failure for your test.\r\n\r\n![Failure](https://s3.amazonaws.com/hashrocket-blog-production/kiwi-example-1.png)\r\nNow that you know that XCTest is working, go ahead and remove this file because we won't use it any longer. \r\n\r\n## CocoaPods\r\n\r\nTo easily manage dependencies we will use [CocoaPods](http://cocoapods.org/). Installation is simple, on terminal:\r\n\r\n`gem install cocoapods`\r\n\r\nInside the project's directory, generate the pod file:\r\n\r\n`pod init`\r\n\r\n## Kiwi\r\n\r\nEdit the generated file 'Podfile' to add Kiwi dependency: \r\n\r\n```objc\r\ntarget \"KiwiExample\" do\r\nend\r\n\r\ntarget \"KiwiExampleTests\" do\r\n  pod 'Kiwi/XCTest'\r\nend\r\n```\r\nInstall dependencies:\r\n\r\n`pod install`\r\n\r\nCocoapods will generate a workspace called 'KiwiExample.xcworkspace'. Make sure to close your Xcode project and open the workspace instead. \r\n\r\nNow you can start writing specs. \r\n\r\n## Writing tests\r\n\r\nTo demonstrate how simple Kiwi syntax is, we will be writing a spec to make sure the sum (+) method is working properly. \r\n\r\nTo create a new test file go to File -\u003e New -\u003e File (or CMD-n).\r\nSelect the option \"Objective-C test case class\" from  the iOS - Cocoa Touch menu and click Next.\r\n\r\n![New File](https://s3.amazonaws.com/hashrocket-blog-production/kiwi-example-2.png)\r\nProvide a name for the new file. For our app example we will call it \"MathSpec\". \r\n\r\nSelect the subclass type, we will be using \"XCTestCase\", click next and choose were the file will be stored. Make sure the checkbox option \"KiwiExampleTest\" target is checked and click to create the file. \r\n\r\n![Create new file](https://s3.amazonaws.com/hashrocket-blog-production/kiwi-example-3.png)\r\nXcode will open the generated file automatically. \r\n\r\nThis file contains a default template based on the XCTestCase. Since we are not using any of this, you can remove all the content and use the following code: \r\n\r\n```objc\r\n#import \"Kiwi.h\"\r\n\r\nSPEC_BEGIN(MathSpec)\r\n\r\ndescribe(@\"sum\", ^{\r\n  context(@\"with 2 numbers\", ^{\r\n    it(@\"returns the sum of the two numbers\", ^{\r\n      [[@(40 + 2) should] equal:@42];\r\n    });\r\n  });\r\n});\r\n\r\nSPEC_END\r\n```\r\n\r\nNow use CMD+u to run your spec and Xcode will display the results for your test. \r\n\r\n![Test passed](https://s3.amazonaws.com/hashrocket-blog-production/kiwi-example-4.png)\r\n\r\nAs you can see, the DSL to write specs is pretty much the same as in [RSpec]. You can call the methods \"describe\", \"context\", \"it\" with a description and a block as the arguments. You can also do the assertions with any object with the method \"should*\". Mocks and stubs are also available. To more information, go to the [Kiwi's wiki](https://github.com/allending/Kiwi/wiki).\r\n\r\n[RSpec]: https://relishapp.com/rspec \"RSpec\"","content_text":"It is well known that we at Hashrocket are advocates for the testing culture. After years of working with Ruby and Rails we've tried all kinds of testing frameworks, and there's no question that we like RSpec.\n\nWe feel that testing iOS apps should be similar, and we've being trying out different testing frameworks. Among them is Kiwi which has a [RSpec]-like syntax for Objective-C.\n\nIt was a nightmare to setup Kiwi 1.0 with Xcode 4. However, everything is much easier with Kiwi 2.0 and Xcode 5.\n\nYou will find extensive documentation about the subject at Kiwi's wiki, but we would like to show you a simpler approach. \nCreating the project\n\nCreate a new empty Xcode 5 project. For testing propose our app will be called \"KiwiExample\". \n\nXcode 5 will create a target called \"KiwiExampleTests\" for unit testing using framework XCTest. It will also generate a test case file containing 1 test example. \n\nTo run the test go to \"Product\" -\u0026gt; \"Test\" on Xcode menu or use the shortcut \"CMD+u\". \n\nIf everything is correct you will get a \"No implementation\" failure for your test.\n\n\nNow that you know that XCTest is working, go ahead and remove this file because we won't use it any longer. \nCocoaPods\n\nTo easily manage dependencies we will use CocoaPods. Installation is simple, on terminal:\n\ngem install cocoapods\n\nInside the project's directory, generate the pod file:\n\npod init\nKiwi\n\nEdit the generated file 'Podfile' to add Kiwi dependency: \ntarget \"KiwiExample\" do\nend\n\ntarget \"KiwiExampleTests\" do\n  pod 'Kiwi/XCTest'\nend\n\nInstall dependencies:\n\npod install\n\nCocoapods will generate a workspace called 'KiwiExample.xcworkspace'. Make sure to close your Xcode project and open the workspace instead. \n\nNow you can start writing specs. \nWriting tests\n\nTo demonstrate how simple Kiwi syntax is, we will be writing a spec to make sure the sum (+) method is working properly. \n\nTo create a new test file go to File -\u0026gt; New -\u0026gt; File (or CMD-n).\nSelect the option \"Objective-C test case class\" from  the iOS - Cocoa Touch menu and click Next.\n\n\nProvide a name for the new file. For our app example we will call it \"MathSpec\". \n\nSelect the subclass type, we will be using \"XCTestCase\", click next and choose were the file will be stored. Make sure the checkbox option \"KiwiExampleTest\" target is checked and click to create the file. \n\n\nXcode will open the generated file automatically. \n\nThis file contains a default template based on the XCTestCase. Since we are not using any of this, you can remove all the content and use the following code: \n#import \"Kiwi.h\"\n\nSPEC_BEGIN(MathSpec)\n\ndescribe(@\"sum\", ^{\n  context(@\"with 2 numbers\", ^{\n    it(@\"returns the sum of the two numbers\", ^{\n      [[@(40 + 2) should] equal:@42];\n    });\n  });\n});\n\nSPEC_END\n\nNow use CMD+u to run your spec and Xcode will display the results for your test. \n\n\n\nAs you can see, the DSL to write specs is pretty much the same as in [RSpec]. You can call the methods \"describe\", \"context\", \"it\" with a description and a block as the arguments. You can also do the assertions with any object with the method \"should*\". Mocks and stubs are also available. To more information, go to the Kiwi's wiki.\n\n[RSpec]: https://relishapp.com/rspec \"RSpec\"\n","summary":"It is well known that we at Hashrocket are advocates for the testing culture. After years of working with Ruby and Rails we've tried all kinds of testing frameworks, and there's no question that we like RSpec.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/160/3801727532_cb8ed8ca5b_z.jpg","date_published":"2014-02-03T09:00:00-05:00","data_modified":"2014-01-23T16:58:45-05:00","author":{"name":"Gabriel Reis","url":"https://hashrocket.com/team/gabriel-reis","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/47/gabriel-reis.jpg"},"tags":["iOS","Testing","Mobile"]},{"id":"https://hashrocket.com/blog/posts/introducing-constraintformatter","url":"https://hashrocket.com/blog/posts/introducing-constraintformatter","title":"Introducing ConstraintFormatter","content_html":"We all know how painful and verbose building a layout in iOS can be.\n\nOn a [previous blog post](http://hashrocket.com/blog/posts/using-auto-layout-for-ios) about this subject [Gabriel](http://hashrocket.com/blog/rocketeers/gabriel-reis) presented a library called [Masonry](https://github.com/cloudkite/Masonry) which makes, using Gabriel's words, attribute constraints succinct.\r\n\r\nWhile working on that blog post and discussing it around the office, the idea for [ConstraintFormatter](https://github.com/greis/ConstraintFormatter) was born.\r\n\r\nWith [ConstraintFormatter](https://github.com/greis/ConstraintFormatter) you describe your visual constraints and constraints based on attributes for Auto Layout in a single place. \r\n\r\nIn order to make it easier to understand, I've changed the [ViewsAlignment](https://github.com/greis/ViewsAlignmentExample) example app shown earlier to use our [shiny new library](https://github.com/greis/ConstraintFormatter). You can check all changes on this [commit](https://github.com/greis/ViewsAlignmentExample/commit/fbf46f1a15f04fb9b5e727bd50b4d1b19da70c95).\r\n\r\nTo recap, the app example consists of one simple screen with:\r\n\r\n* UIImageView for the group picture\r\n* UIImageView for the logo\r\n* UILabel for the company name\r\n* UIView with white background color as the container for the logo and name\r\n\r\nThat is what it should look like:\r\n\r\n![app](http://s3.amazonaws.com/hashrocket-blog-production/ios-constraints-1.jpg)\r\n\r\n## App Internals ##\r\n\r\nTo draw that screen we organized this app with a ViewController called [RootViewController.m](https://github.com/greis/ViewsAlignmentExample/blob/use_constraint_formatter/ViewsAlignmentExample/RootViewController.m),\r\nwhere we describe the background, and a view called [LogoView.m](https://github.com/greis/ViewsAlignmentExample/blob/use_constraint_formatter/ViewsAlignmentExample/LogoView.m), where we describe the logo and label on the bottom. \r\n\r\n### Changes on the RootViewController.m ###\r\n\r\n\r\nThe first step is to import the library:\r\n\r\n```objc\r\n#import \"ConstraintFormatter.h\"\r\n```\r\n\r\nThen, go ahead and remove all  setTranslatesAutoresizingMaskIntoConstraints:NO from your code because [ConstraintFormatter](https://github.com/greis/ConstraintFormatter) will add it in all views declared on your constraints. Pretty handy, don't you think? \r\n\r\nThe main changes are:\r\n\r\n* describe the views\r\n* describe the metrics\r\n* describe the formats\r\n\r\n```objc\r\n-(void)addConstraints {\r\n  id views = @{@\"logo\": self.logoView, @\"background\": self.backgroundView};\r\n  id metrics = @{@\"margin\": @10};\r\n  id formats = @[@\"logo.centerX == superview.centerX\",\r\n                 @\"logo.bottom == superview.bottom\",                                            \r\n                 @\"H:|[background]|\",\r\n                 @\"V:|[background]|\"];\r\n}\r\n```\r\n\r\nWe are declaring constraints to the \"logo\" and \"background\" views as following: \r\n\r\n- logo centerX (horizontal center) position is the same as the superview centerX (the whole screen)\r\n- the bottom of the logo is the same as the bottom of the superview\r\n- the background will fill the whole screen vertically\r\n- the background will fill the whole screen horizontally\r\n\r\nYour constraints are:\r\n\r\n```objc\r\n[self.view addConstraintsWithFormats:formats views:views metrics:metrics];\r\n```\r\n\r\n### Changes on the LogoView.m ###\r\n\r\nOnce again, we import the library:\r\n\r\n```objc\r\n#import \"ConstraintFormatter.h\"\r\n```\r\n\r\nClean up your code by removing the  ```objc setTranslatesAutoresizingMaskIntoConstraints:NO ``` \r\n\r\nDescribe our constraints for this view:\r\n\r\n```objc\r\n-(void)addConstraints {\r\n  id views = @{@\"image\": self.imageView, @\"label\": self.label};\r\n  id metrics = @{@\"margin\": @6};\r\n  id formats = @[@\"label.centerY == superview.centerY\",\r\n                 @\"H:|-margin-[image]-margin-[label]-margin-|\",\r\n                 @\"V:|-margin-[image]-margin-|\"];\r\n  \r\n  [self addConstraintsWithFormats:formats views:views metrics:metrics];\r\n  \r\n}\r\n```\r\n\r\nHere we have a view we call \"image\" (for the logo) e \"label\" (for the Hashrocket text) and the rules are: \r\n\r\n- label centerY (vertical center) is equal to superview centerY (note that superview here is the LogoView, the white area on the bottom of the screen).\r\n- Horizontally we have a margin, the image, a margin, the text, and a final margin. Meaning: I want the image on the left, the label on the right, and the spacing between them is 6 points. For the image, add a 6 point margin on the left side and add a 6 point margin on the right of the label.\r\n- Vertically we have a margin, the image, and a margin. Meaning: add the image within 6 points from the top and 6 points from the bottom. \r\n\r\nI don't know about you, but it seems much easier to me to describe my elements this way and even easier to understand it months later when I have to look at this code again. \r\n\r\nWhat do you think?","content_text":"We all know how painful and verbose building a layout in iOS can be.\n\nOn a previous blog post about this subject Gabriel presented a library called Masonry which makes, using Gabriel's words, attribute constraints succinct.\n\nWhile working on that blog post and discussing it around the office, the idea for ConstraintFormatter was born.\n\nWith ConstraintFormatter you describe your visual constraints and constraints based on attributes for Auto Layout in a single place. \n\nIn order to make it easier to understand, I've changed the ViewsAlignment example app shown earlier to use our shiny new library. You can check all changes on this commit.\n\nTo recap, the app example consists of one simple screen with:\n\n\nUIImageView for the group picture\nUIImageView for the logo\nUILabel for the company name\nUIView with white background color as the container for the logo and name\n\n\nThat is what it should look like:\n\n\nApp Internals\n\nTo draw that screen we organized this app with a ViewController called RootViewController.m,\nwhere we describe the background, and a view called LogoView.m, where we describe the logo and label on the bottom. \nChanges on the RootViewController.m\n\nThe first step is to import the library:\n#import \"ConstraintFormatter.h\"\n\nThen, go ahead and remove all  setTranslatesAutoresizingMaskIntoConstraints:NO from your code because ConstraintFormatter will add it in all views declared on your constraints. Pretty handy, don't you think? \n\nThe main changes are:\n\n\ndescribe the views\ndescribe the metrics\ndescribe the formats\n\n-(void)addConstraints {\n  id views = @{@\"logo\": self.logoView, @\"background\": self.backgroundView};\n  id metrics = @{@\"margin\": @10};\n  id formats = @[@\"logo.centerX == superview.centerX\",\n                 @\"logo.bottom == superview.bottom\",                                            \n                 @\"H:|[background]|\",\n                 @\"V:|[background]|\"];\n}\n\nWe are declaring constraints to the \"logo\" and \"background\" views as following: \n\n\nlogo centerX (horizontal center) position is the same as the superview centerX (the whole screen)\nthe bottom of the logo is the same as the bottom of the superview\nthe background will fill the whole screen vertically\nthe background will fill the whole screen horizontally\n\n\nYour constraints are:\n[self.view addConstraintsWithFormats:formats views:views metrics:metrics];\nChanges on the LogoView.m\n\nOnce again, we import the library:\n#import \"ConstraintFormatter.h\"\n\nClean up your code by removing the  objc setTranslatesAutoresizingMaskIntoConstraints:NO \n\nDescribe our constraints for this view:\n-(void)addConstraints {\n  id views = @{@\"image\": self.imageView, @\"label\": self.label};\n  id metrics = @{@\"margin\": @6};\n  id formats = @[@\"label.centerY == superview.centerY\",\n                 @\"H:|-margin-[image]-margin-[label]-margin-|\",\n                 @\"V:|-margin-[image]-margin-|\"];\n\n  [self addConstraintsWithFormats:formats views:views metrics:metrics];\n\n}\n\nHere we have a view we call \"image\" (for the logo) e \"label\" (for the Hashrocket text) and the rules are: \n\n\nlabel centerY (vertical center) is equal to superview centerY (note that superview here is the LogoView, the white area on the bottom of the screen).\nHorizontally we have a margin, the image, a margin, the text, and a final margin. Meaning: I want the image on the left, the label on the right, and the spacing between them is 6 points. For the image, add a 6 point margin on the left side and add a 6 point margin on the right of the label.\nVertically we have a margin, the image, and a margin. Meaning: add the image within 6 points from the top and 6 points from the bottom. \n\n\nI don't know about you, but it seems much easier to me to describe my elements this way and even easier to understand it months later when I have to look at this code again. \n\nWhat do you think?\n","summary":"We all know how painful and verbose building a layout in iOS can be.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/155/constraints.png","date_published":"2014-01-09T09:00:00-05:00","data_modified":"2014-01-10T11:29:37-05:00","author":{"name":"Thais Camilo","url":"https://hashrocket.com/team/thais-camilo","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/46/thais-camilo.jpg"},"tags":["iOS","Mobile"]},{"id":"https://hashrocket.com/blog/posts/using-auto-layout-for-ios","url":"https://hashrocket.com/blog/posts/using-auto-layout-for-ios","title":"Using Auto Layout for iOS","content_html":"Auto Layout is a powerful system for iOS that lets you write flexible UIs for any device and orientation without having to deal with the frame of the views. You won't need to do math with CGRects and CGPoints anymore.\n\nTo explain how it works, let's create a sample app for this simple screen:\r\n\r\n![](//s3.amazonaws.com/hashrocket-blog-production/ios-constraints-1.jpg)\r\n\r\nWe can see the following UI elements that are present:\r\n\r\n* UIImageView for the group picture\r\n* UIImageView for the logo\r\n* UILabel for the company name\r\n* UIView with white background color as the container for the logo and name\r\n\r\nBefore Auto Layout we would look at this screen and say that:\r\n\r\n* group picture size is 568x320 and is located at position (0,0)\r\n* container size is 150x56 and located at position (115,264)\r\n* logo size is 44x44 and located inside container at position (6,6)\r\n* label size is 88x25 and located inside container at position (56,21)\r\n\r\nBut with Auto Layout we can start to think how the views are related to each other and not care about frame sizes and points. Analyzing the screen, we can see the following rules:\r\n\r\n![](//s3.amazonaws.com/hashrocket-blog-production/ios-constraints-2.jpg)\r\n\r\n1. group picture has the same size as the screen\r\n2. container view is at the bottom of the screen\r\n3. container view is centered on x-axis\r\n4. width of container view is margin of 6px + width of logo + margin of 6px + width of label + margin of 6px\r\n5. height of container view is margin of 6px + height of logo + margin of 6px\r\n6. logo and label are centered on y-axis\r\n\r\nNow it's time to implement the screen and make the code that understands these rules. The first step is to create a controller that contains a UIImageView to display the group picture:\r\n\r\n```objc\r\n@interface RootViewController () {\r\n  UIImageView *_backgroundView;\r\n}\r\n@end\r\n\r\n@implementation RootViewController\r\n\r\n- (void)viewDidLoad {\r\n  [super viewDidLoad];\r\n  [self.view addSubview:self.backgroundView];\r\n}\r\n\r\n-(UIImageView *)backgroundView {\r\n  if (!_backgroundView) {\r\n    _backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"group-picture\"]];\r\n    [_backgroundView setContentMode:UIViewContentModeScaleAspectFill];\r\n  }\r\n  return _backgroundView;\r\n}\r\n\r\n@end\r\n```\r\nNote that we didn't set the frame of the UIImageView since we will be using Auto Layout.\r\n\r\nNow let's create the first constraints to satisfy rule 1 \"group picture has the same size as the screen\":\r\n\r\n```objc\r\n- (void)viewDidLoad {\r\n  ...\r\n  [self addConstraints];\r\n}\r\n\r\n-(UIImageView *)backgroundView {\r\n  ...\r\n  [_backgroundView setTranslatesAutoresizingMaskIntoConstraints:NO];\r\n}\r\n\r\n-(void)addConstraints {\r\n  id views = @{@\"background\": self.backgroundView};\r\n  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"H:|[background]|\" options:0 metrics:nil views:views]];\r\n  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:|[background]|\" options:0 metrics:nil views:views]];\r\n}\r\n```\r\n\r\nInside viewDidLoad we call our new method addConstraints that contains 2 constraints. On this example, we are using the [visual format language] (https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage/VisualFormatLanguage.html) to define the constraints. \r\n\r\nThe first one is \"H:|[background]|\":\r\n\r\n* \"H:\" means that this constraint is for the horizontal layout, the x-axis\r\n* \"|\" is a reference to the view which the constraints are being added. In our case is the controller's view.\r\n* \"[background]\" is a reference to the backgroundView\r\n\r\nBy default, the controller's view size is the same size of the screen. So when we add the \"[background]\" surrounded by \"|\", and prepended with \"H:\", we are saying that the width of the backgroundView will be the same width of the screen. The other constraint \"V:|[background]|\" is the same idea but for the vertical layout, and defines the height of the backgroundView.\r\n\r\nAnother thing to mention is that we had to call setTranslatesAutoresizingMaskIntoConstraints:NO in the backgroundView. iOS 6 introduced Auto Layout and before it, if we wanted to create flexible views we would have to use autoresizing masks. To keep compatibility with previous iOS versions, all autoresizing masks are translated into constraints by default. If you want to use Auto Layout you have to disable this in all views that are referenced in the constraints otherwise you will get some exceptions related to conflicting constraints.\r\n\r\nNow it's time to create the container view. We could do everything inside the controller, but in this case it's better to extract all the elements to a custom subview. So we create a subclass of UIView called LogoView that contains the logo and the label.\r\n\r\n```objc\r\n@interface LogoView () {\r\n  UIImageView *_imageView;\r\n  UILabel *_label;\r\n}\r\n@end\r\n\r\n@implementation LogoView\r\n\r\n- (id)init {\r\n  self = [super init];\r\n  if (self) {\r\n    [self setBackgroundColor:[UIColor colorWithWhite:1 alpha:0.8]];\r\n    [self addSubview:self.imageView];\r\n    [self addSubview:self.label];\r\n  }\r\n  return self;\r\n}\r\n\r\n-(UIImageView *)imageView {\r\n  if (!_imageView) {\r\n    _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"hr_logo_rocket\"]];\r\n    [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO];\r\n  }\r\n  return _imageView;\r\n}\r\n\r\n-(UILabel *)label {\r\n  if (!_label) {\r\n    _label = [[UILabel alloc] init];\r\n    [_label setText:@\"Hashrocket\"];\r\n    [_label setTranslatesAutoresizingMaskIntoConstraints:NO];\r\n  }\r\n  return _label;\r\n}\r\n```\r\n\r\nTo satisfy the rules 4, 5 and 6 we just need 2 visual constraints:\r\n\r\n```objc\r\n-(void)addConstraints {\r\n  id views = @{@\"image\": self.imageView, @\"label\": self.label};\r\n  id metrics = @{@\"margin\": @6};\r\n  \r\n  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-margin-[image]-margin-[label]-margin-|\" options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];\r\n  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-margin-[image]-margin-|\" options:0 metrics:metrics views:views]];  \r\n}\r\n```\r\n\r\nTo explain the first constraint we have to understand how UIImage and UILabel define their size. By default, the width and height of the UIImageView are the actual width and height of the .png file. The UILabel width and height are calculated by the font size and text length.\r\n\r\nNow that we know this, we can use the visual format and put both views side by side and separate them with some margin that comes from a metrics option. The pipes surrounding these visual constraints ensure everything is laid out properly.\r\n\r\nWhat we have to understand here is that the pipes in this example behave different than the first example. In both examples, the pipes represent the superview of the views we're laying out.  Where things differ is that in the first example, anchoring our visual constraint with the pipes cause the subview to set it's width equal to the superview, while in this example the effect is to cause the superview's size to change based on the subview's size. \r\n\r\nThis is really cool! If later we want to update the label text to \"Hashrocket 2013\", the LogoView will automatically change it's size, because the UILabel increased it's width.\r\n\r\nAlso note that we passed the option NSLayoutFormatAlignAllCenterY to the first constraint. This option makes both views to be aligned on the y-axis. This satisfies rule 6.\r\n\r\nThe second constraint defines the height of the LogoView. Since the image height is greater than the label height, we can use the same idea as the previous constraint and only use the \"[image]\" height to define the LogoView height.\r\n\r\nNow it's time to add this custom view to the RootViewController and position it on the screen to satisfy rules 2 and 3:\r\n\r\n```objc\r\n- (void)viewDidLoad {\r\n  ...\r\n  [self.view addSubview:self.logoView];\r\n  ...\r\n}\r\n\r\n-(LogoView *)logoView {\r\n  if (!_logoView) {\r\n    _logoView = [[LogoView alloc] init];\r\n    [_logoView setTranslatesAutoresizingMaskIntoConstraints:NO];\r\n  }\r\n  return _logoView;\r\n}\r\n\r\n-(void)addConstraints {\r\n  id views = @{@\"logo\": self.logoView, ...};\r\n  \r\n  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:[logo]|\" options:0 metrics:nil views:views]];\r\n  [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];\r\n  ...\r\n}\r\n```\r\n\r\nThe first constraint \"V:[logo]|\" uses only one pipe at the end. This means that the bottom of the logoView is at the bottom of the controller's view.\r\n\r\nTo satisfy rule 3 \"container view is centered on x-axis\" we can't use the visual format. We have to create a constraint based on attributes. The constraint we created says the logoView's centerX attribute is equal to the controller view's centerX attribute.\r\n\r\nThe visual format is really cool and easy to read, but it's not enough to describe more complex relationships between views. It is worth noting that any constraint created using the visual format could be created using constraintWithItem.\r\n\r\nFor instance, the visual format constraint “V:[logo]|” could be rewritten to use constraintWithItem, like this:\r\n\r\n```objc\r\n[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];\r\n```\r\n\r\nBut now the code starts to become more verbose and not so easy to read as the visual format. That's when the library [Masonry](https://github.com/cloudkite/Masonry) comes in. It's a DSL that makes the attribute constraints succinct. So the same example we could write as:\r\n\r\n```objc\r\n[self.logoView mas_makeConstraints:^(MASConstraintMaker *make) {\r\n  make.bottom.equalTo(self.view);\r\n  make.centerX.equalTo(self.view);\r\n}];\r\n```\r\n\r\nAnd if we refactor the addConstraints method to also use Masonry to layout the backgroundView, we would finally have something like this:\r\n\r\n```objc\r\n-(void)addConstraints {\r\n  [self.backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {\r\n    make.edges.equalTo(self.view);\r\n  }];\r\n  \r\n  [self.logoView mas_makeConstraints:^(MASConstraintMaker *make) {\r\n    make.bottom.equalTo(self.view);\r\n    make.centerX.equalTo(self.view);\r\n  }];\r\n}\r\n```\r\nMuch nicer!\r\n\r\nThis sample app is available on [github](https://github.com/greis/ViewsAlignmentExample) if you want to run it.\r\n\r\nAuto Layout is a great way to write flexible and maintainable views dependencies. In some cases it's better to use the visual format, but when it's not enough you can go straight to Masonry and write beautiful constraints!\r\n\r\nUpdate: Also check out this other blog post where we introduce our new library [ConstraintFormatter](http://hashrocket.com/blog/posts/introducing-constraintformatter) that unify visual constraints and constraints based on attributes.","content_text":"Auto Layout is a powerful system for iOS that lets you write flexible UIs for any device and orientation without having to deal with the frame of the views. You won't need to do math with CGRects and CGPoints anymore.\n\nTo explain how it works, let's create a sample app for this simple screen:\n\n\n\nWe can see the following UI elements that are present:\n\n\nUIImageView for the group picture\nUIImageView for the logo\nUILabel for the company name\nUIView with white background color as the container for the logo and name\n\n\nBefore Auto Layout we would look at this screen and say that:\n\n\ngroup picture size is 568x320 and is located at position (0,0)\ncontainer size is 150x56 and located at position (115,264)\nlogo size is 44x44 and located inside container at position (6,6)\nlabel size is 88x25 and located inside container at position (56,21)\n\n\nBut with Auto Layout we can start to think how the views are related to each other and not care about frame sizes and points. Analyzing the screen, we can see the following rules:\n\n\n\n\ngroup picture has the same size as the screen\ncontainer view is at the bottom of the screen\ncontainer view is centered on x-axis\nwidth of container view is margin of 6px + width of logo + margin of 6px + width of label + margin of 6px\nheight of container view is margin of 6px + height of logo + margin of 6px\nlogo and label are centered on y-axis\n\n\nNow it's time to implement the screen and make the code that understands these rules. The first step is to create a controller that contains a UIImageView to display the group picture:\n@interface RootViewController () {\n  UIImageView *_backgroundView;\n}\n@end\n\n@implementation RootViewController\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n  [self.view addSubview:self.backgroundView];\n}\n\n-(UIImageView *)backgroundView {\n  if (!_backgroundView) {\n    _backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"group-picture\"]];\n    [_backgroundView setContentMode:UIViewContentModeScaleAspectFill];\n  }\n  return _backgroundView;\n}\n\n@end\n\nNote that we didn't set the frame of the UIImageView since we will be using Auto Layout.\n\nNow let's create the first constraints to satisfy rule 1 \"group picture has the same size as the screen\":\n- (void)viewDidLoad {\n  ...\n  [self addConstraints];\n}\n\n-(UIImageView *)backgroundView {\n  ...\n  [_backgroundView setTranslatesAutoresizingMaskIntoConstraints:NO];\n}\n\n-(void)addConstraints {\n  id views = @{@\"background\": self.backgroundView};\n  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"H:|[background]|\" options:0 metrics:nil views:views]];\n  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:|[background]|\" options:0 metrics:nil views:views]];\n}\n\nInside viewDidLoad we call our new method addConstraints that contains 2 constraints. On this example, we are using the visual format language to define the constraints. \n\nThe first one is \"H:|[background]|\":\n\n\n\"H:\" means that this constraint is for the horizontal layout, the x-axis\n\"|\" is a reference to the view which the constraints are being added. In our case is the controller's view.\n\"[background]\" is a reference to the backgroundView\n\n\nBy default, the controller's view size is the same size of the screen. So when we add the \"[background]\" surrounded by \"|\", and prepended with \"H:\", we are saying that the width of the backgroundView will be the same width of the screen. The other constraint \"V:|[background]|\" is the same idea but for the vertical layout, and defines the height of the backgroundView.\n\nAnother thing to mention is that we had to call setTranslatesAutoresizingMaskIntoConstraints:NO in the backgroundView. iOS 6 introduced Auto Layout and before it, if we wanted to create flexible views we would have to use autoresizing masks. To keep compatibility with previous iOS versions, all autoresizing masks are translated into constraints by default. If you want to use Auto Layout you have to disable this in all views that are referenced in the constraints otherwise you will get some exceptions related to conflicting constraints.\n\nNow it's time to create the container view. We could do everything inside the controller, but in this case it's better to extract all the elements to a custom subview. So we create a subclass of UIView called LogoView that contains the logo and the label.\n@interface LogoView () {\n  UIImageView *_imageView;\n  UILabel *_label;\n}\n@end\n\n@implementation LogoView\n\n- (id)init {\n  self = [super init];\n  if (self) {\n    [self setBackgroundColor:[UIColor colorWithWhite:1 alpha:0.8]];\n    [self addSubview:self.imageView];\n    [self addSubview:self.label];\n  }\n  return self;\n}\n\n-(UIImageView *)imageView {\n  if (!_imageView) {\n    _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"hr_logo_rocket\"]];\n    [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO];\n  }\n  return _imageView;\n}\n\n-(UILabel *)label {\n  if (!_label) {\n    _label = [[UILabel alloc] init];\n    [_label setText:@\"Hashrocket\"];\n    [_label setTranslatesAutoresizingMaskIntoConstraints:NO];\n  }\n  return _label;\n}\n\nTo satisfy the rules 4, 5 and 6 we just need 2 visual constraints:\n-(void)addConstraints {\n  id views = @{@\"image\": self.imageView, @\"label\": self.label};\n  id metrics = @{@\"margin\": @6};\n\n  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-margin-[image]-margin-[label]-margin-|\" options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];\n  [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-margin-[image]-margin-|\" options:0 metrics:metrics views:views]];  \n}\n\nTo explain the first constraint we have to understand how UIImage and UILabel define their size. By default, the width and height of the UIImageView are the actual width and height of the .png file. The UILabel width and height are calculated by the font size and text length.\n\nNow that we know this, we can use the visual format and put both views side by side and separate them with some margin that comes from a metrics option. The pipes surrounding these visual constraints ensure everything is laid out properly.\n\nWhat we have to understand here is that the pipes in this example behave different than the first example. In both examples, the pipes represent the superview of the views we're laying out.  Where things differ is that in the first example, anchoring our visual constraint with the pipes cause the subview to set it's width equal to the superview, while in this example the effect is to cause the superview's size to change based on the subview's size. \n\nThis is really cool! If later we want to update the label text to \"Hashrocket 2013\", the LogoView will automatically change it's size, because the UILabel increased it's width.\n\nAlso note that we passed the option NSLayoutFormatAlignAllCenterY to the first constraint. This option makes both views to be aligned on the y-axis. This satisfies rule 6.\n\nThe second constraint defines the height of the LogoView. Since the image height is greater than the label height, we can use the same idea as the previous constraint and only use the \"[image]\" height to define the LogoView height.\n\nNow it's time to add this custom view to the RootViewController and position it on the screen to satisfy rules 2 and 3:\n- (void)viewDidLoad {\n  ...\n  [self.view addSubview:self.logoView];\n  ...\n}\n\n-(LogoView *)logoView {\n  if (!_logoView) {\n    _logoView = [[LogoView alloc] init];\n    [_logoView setTranslatesAutoresizingMaskIntoConstraints:NO];\n  }\n  return _logoView;\n}\n\n-(void)addConstraints {\n  id views = @{@\"logo\": self.logoView, ...};\n\n  [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:[logo]|\" options:0 metrics:nil views:views]];\n  [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];\n  ...\n}\n\nThe first constraint \"V:[logo]|\" uses only one pipe at the end. This means that the bottom of the logoView is at the bottom of the controller's view.\n\nTo satisfy rule 3 \"container view is centered on x-axis\" we can't use the visual format. We have to create a constraint based on attributes. The constraint we created says the logoView's centerX attribute is equal to the controller view's centerX attribute.\n\nThe visual format is really cool and easy to read, but it's not enough to describe more complex relationships between views. It is worth noting that any constraint created using the visual format could be created using constraintWithItem.\n\nFor instance, the visual format constraint “V:[logo]|” could be rewritten to use constraintWithItem, like this:\n[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.logoView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];\n\nBut now the code starts to become more verbose and not so easy to read as the visual format. That's when the library Masonry comes in. It's a DSL that makes the attribute constraints succinct. So the same example we could write as:\n[self.logoView mas_makeConstraints:^(MASConstraintMaker *make) {\n  make.bottom.equalTo(self.view);\n  make.centerX.equalTo(self.view);\n}];\n\nAnd if we refactor the addConstraints method to also use Masonry to layout the backgroundView, we would finally have something like this:\n-(void)addConstraints {\n  [self.backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {\n    make.edges.equalTo(self.view);\n  }];\n\n  [self.logoView mas_makeConstraints:^(MASConstraintMaker *make) {\n    make.bottom.equalTo(self.view);\n    make.centerX.equalTo(self.view);\n  }];\n}\n\nMuch nicer!\n\nThis sample app is available on github if you want to run it.\n\nAuto Layout is a great way to write flexible and maintainable views dependencies. In some cases it's better to use the visual format, but when it's not enough you can go straight to Masonry and write beautiful constraints!\n\nUpdate: Also check out this other blog post where we introduce our new library ConstraintFormatter that unify visual constraints and constraints based on attributes.\n","summary":"Auto Layout is a powerful system for iOS that lets you write flexible UIs for any device and orientation without having to deal with the frame of the views. You won't need to do math with CGRects and CGPoints anymore.\n","image":"https://dkj231ikyz7c1.cloudfront.net/uploads/blog/post/image/145/autolayout.png","date_published":"2013-10-10T09:00:00-04:00","data_modified":"2014-02-06T10:23:02-05:00","author":{"name":"Gabriel Reis","url":"https://hashrocket.com/team/gabriel-reis","avatar":"https://dkj231ikyz7c1.cloudfront.net/uploads/rocketeer/profile_image/47/gabriel-reis.jpg"},"tags":["iOS","Mobile"]}]}