In this series, you're learning how to use React Native to create page layouts commonly used in mobile apps. The layouts you're creating won't be functional—instead, the main focus of this series is to get your hands dirty in laying out content in your React Native apps.
If you're new to laying out React Native apps or styling in general, check out my previous tutorial:
To follow along with this series, I challenge you to try recreating each screen by yourself first, before you read my step-by-step instructions in the tutorial. You won't really benefit much from this tutorial just by reading it! Try first before looking up the answers here. If you succeed in making it look like the original screen, compare your implementation to mine. Then decide for yourself which one is better!
In this third post of the series, you'll create the following photo gallery page:
Galleries are often used to display a collection of related content in such a way that only the necessary information is presented. Most of the time this includes a photo, a title, and other relevant information.
Here are a couple of examples of this type of layout being used in the wild:
Project Setup
The first step, of course, is to set up a new React Native project:
react-native init react-native-common-screens
Once the project is set up, open the index.android.js file and replace the default code with the following:
import React, { Component } from 'react';
import {
AppRegistry
} from 'react-native';
import Gallery from './src/pages/Gallery';
export default class ReactNativeCommonScreens extends Component {
render() {
return (
<Gallery />
);
}
}
AppRegistry.registerComponent('ReactNativeCommonScreens', () => ReactNativeCommonScreens);
Create a src/pages folder and create a Gallery.js file inside it.
You'll also need the react-native-vector-icons package. This is specifically used for the icons in the footer.
npm install --save react-native-vector-icons
Open the android/app/build.gradle file and add a reference to the package:
dependencies {
//rest of the dependencies are here at the top
compile project(':react-native-vector-icons') //add this
}
Do the same with the android/settings.gradle file by adding the following at the bottom:
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
Open android/app/src/main/java/com/react-native-common-screens/MainApplication.java and import the package:
import java.util.Arrays;
import java.util.List;
import com.oblador.vectoricons.VectorIconsPackage; //add this
Lastly, initialize the package:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new VectorIconsPackage() //add this
);
}
Creating the Gallery Page
Okay, now that you've tried to code the layout yourself (no cheating, right?), I'll show you how I built my implementation.
Unlike the previous two pages, the gallery page needs some images that will serve as its main content. You can go to Google and search for images or download the images from the GitHub repo. All the images that I used are labeled for reuse by their respective owners, so you can freely use them if you want. Once you have the images, save them inside the src/images directory. Due to the way the images will be laid out, all of them should have equal dimensions.
Start by creating the file (src/pages/Gallery.js) and add the boilerplate code:
import React, { Component } from 'react';
import {
StyleSheet,
View,
ScrollView,
Image,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import Button from '../components/Button';
export default class Gallery extends Component {
...
}
This page needs a constructor() function where you define the paths to the images that you want to use. In React Native, the way you refer to images that are inside your working directory is by requiring them just like you would a JavaScript module. It's also important to note that you can't have dynamically generated image paths so you have to supply the actual path by hand.
You don't really need to define these in the state as the values won't change. You could actually define these in a separate file, import it, assign it to a variable, and then use it directly. But for the sake of simplicity, I decided to just put everything in the state.
Inside the render() method, you're going to break the trend of wrapping everything inside a ScrollView component, because the tab component at the lowermost portion of the screen should have a fixed position. This means that even if the photos goes over the available height, the tabs should still stay in place. To achieve this, use a View component to wrap everything and only wrap the collection of photos in a ScrollView. This allows you to apply the scroll only to the container of the collection of photos:
Now you may start to see a pattern here. Every time you need to use JavaScript code inside the render() function, you should create a separate function to hold that code, instead of putting it directly inside the render() function. This keeps it lean and clean.
Now let's move on to the styling. Although a ScrollView isn't used to wrap everything this time, it's important to note that you still have to supply flex: 1 to the main container so that it consumes the entirety of the available space.
The renderGallery() function is very similar to the renderWeeks() function that we used in the previous tutorial, which we used to render a calendar page. If you want a refresher on how that works, go ahead and read over the previous tutorial on calendar pages. What you need to know is that resizeMode is applied to the Image. In this case, it's set to cover, which makes the image occupy the entire available space of its container, while still maintaining its aspect ratio. This results in the image getting slightly blown up for devices with larger screens if the original image is smaller.
Finally, here is the styling for each row (item) and photo (photo). Note the use of flex: 1 on the actual photo. This is done because the Image component itself is its own container. You want the container itself to occupy half of the available space for each row—that's why a flex property should be assigned. If this isn't done, only the dimensions needed by the photo will be consumed, and the resizeMode that you added earlier won't even have an effect.
That's it! In this tutorial you learned how to implement the layout for a gallery page. We focused on how to deal with images when it comes to laying out your React Native apps. Often you have to use a combination of flex and resizeMode in order to make images flow the way you want them to. How did my solution compare to your own? Let us know in the discussion forum below.
In an upcoming tutorial, you'll learn how to implement the layout commonly used in news apps. In the meantime, check out some of our other tutorials on React Native and Flexbox!
CSS, despite its relatively low perceived skill ceiling, always seems to have a killer feature up its sleeve. Remember how media queries made responsive...
React Native, created by Facebook, lets you write native mobile apps in modern JavaScript. React Native apps will be transformed into native views specific...
Are you looking to improve your flexbox knowledge and at the same time learn how to build easily an attractive and unique layout? If so, be sure to read this...
Animations can breath life into your app and make your UIs more intuitive. In this tutorial, you'll learn how to implement different kinds of animations in...
Are you a hybrid app developer wanting to include face detection into your app, but you don't have any idea where to start? As a start, you could read An...
Firebase's goal is to help developers build better apps and grow them into successful businesses. By taking care of your app back-end or infrastructure, Firebase lets you focus on solving problems for your users. The new features announced at the Firebase Dev Summit this November were centered around Crash Reporting, Analytics, and support for game developers. In this article, I will give you a breakdown of what was announced and how to get started with these tools.
Firebase Crash Reporting
Since it was released at Google I/O, this has been a beta product. But Firebase Crash Reporting is now out of beta! These are the new updates that come with the full release of Firebase Crash Reporting.
Improved user workflow: You can now mark errors as fixed and track which ones were fixed by you.
Email alerts: You can now get an email notification whenever a new crash happens. You can get notification of new issues or issues that have resurfaced after having been fixed.
Instant reporting: Previously, any time a crash happened on your user's device, it would take about 20 minutes to show on the dashboard. But now you can get the report instantly.
Detailed insight with Analytics: Instead of just showing the errors, you can now see the context in which it happened. For example, if you have an app where an error occurred when your user was creating his/her profile, you can use Firebase Analytics to gain insight into what led to this crash.
At its I/O developers conference about six months ago, Google announced the launch of Firebase Test Lab. With this feature, you can test your app on a wide range of devices and configurations before shipping the final product. This gives you a detailed test result at the end. So what's new? Firebase Test Lab now has:
Eleven new device models.
Ability to test your app on the latest version of Android (currently 7.1).
Ability to run five free tests per day on physical devices and ten free tests per day on virtual devices.
This is an open-source UI library that provides common UI elements when building apps. This library draws on the best practices that Google has learnt over the years. Firebase UI has now been launched as version 1.0.
With this library, you get UI flow for Firebase Authentication, client-side joins and intersections for Realtime Database, as well as integrations with Glide (an open-source image-loading library for Android) that make downloading and displaying images from Firebase Storage a piece of cake. All these integrations help bootstrap your app's UI experience. The library is available for Android, IOS, and Web.
Firebase Analytics now has an integration with Google Data Studio, a service that turns your data into informative dashboards and reports that are easy to read, easy to share, and fully customizable. (Note that Google Data Studio is still in beta.) You can now also export to BigQuery in real time from Analytics. Not only that, but the connection between Firebase Dynamic Links and Analytics has been improved, so that if you use Dynamic link on your Facebook page, Analytics will detect the source as Facebook on the Analytics dashboard.
Unity Plugin for Firebase
An exciting announcement for game developers: Firebase now has a Unity3D plugin and an enhanced C++ SDK. (Most high-quality Android games are still built with C++.) This new feature also opens up some of the core Firebase functionalities such as AdMob, Analytics, Authentication, Realtime Database, Invites and Dynamic Links, Cloud Messaging and Remote Config for use in your game. The Firebase documentation has more information on how to add Firebase to your Unity setup.
Although it was not announced at the Firebase Dev Summit, you should also know that Google Play Services and Firebase will require API level 14 at a minimum starting from early 2017. The next release of these libraries (version 10.2.0) will increase the minimum supported API level from 9 to 14. So when building your app now, it is recommended to set your minimum SDK to be API level 14.
Conclusion
In this article, I told you about the new Firebase features that were announced at the Firebase Dev Summit in Berlin. Firebase has been working to make it easier for developers to code awesome apps, by taking care of the infrastructure and back-end for them. With these additional new features, the developer's job will be easier and faster.
Meanwhile, check out some of our other courses and tutorials on mobile development!
Firebase's goal is to help developers build better apps and grow them into successful businesses. By taking care of your app back-end or infrastructure, Firebase lets you focus on solving problems for your users. The new features announced at the Firebase Dev Summit this November were centered around Crash Reporting, Analytics, and support for game developers. In this article, I will give you a breakdown of what was announced and how to get started with these tools.
Firebase Crash Reporting
Since it was released at Google I/O, this has been a beta product. But Firebase Crash Reporting is now out of beta! These are the new updates that come with the full release of Firebase Crash Reporting.
Improved user workflow: You can now mark errors as fixed and track which ones were fixed by you.
Email alerts: You can now get an email notification whenever a new crash happens. You can get notification of new issues or issues that have resurfaced after having been fixed.
Instant reporting: Previously, any time a crash happened on your user's device, it would take about 20 minutes to show on the dashboard. But now you can get the report instantly.
Detailed insight with Analytics: Instead of just showing the errors, you can now see the context in which it happened. For example, if you have an app where an error occurred when your user was creating his/her profile, you can use Firebase Analytics to gain insight into what led to this crash.
At its I/O developers conference about six months ago, Google announced the launch of Firebase Test Lab. With this feature, you can test your app on a wide range of devices and configurations before shipping the final product. This gives you a detailed test result at the end. So what's new? Firebase Test Lab now has:
Eleven new device models.
Ability to test your app on the latest version of Android (currently 7.1).
Ability to run five free tests per day on physical devices and ten free tests per day on virtual devices.
This is an open-source UI library that provides common UI elements when building apps. This library draws on the best practices that Google has learnt over the years. Firebase UI has now been launched as version 1.0.
With this library, you get UI flow for Firebase Authentication, client-side joins and intersections for Realtime Database, as well as integrations with Glide (an open-source image-loading library for Android) that make downloading and displaying images from Firebase Storage a piece of cake. All these integrations help bootstrap your app's UI experience. The library is available for Android, IOS, and Web.
Firebase Analytics now has an integration with Google Data Studio, a service that turns your data into informative dashboards and reports that are easy to read, easy to share, and fully customizable. (Note that Google Data Studio is still in beta.) You can now also export to BigQuery in real time from Analytics. Not only that, but the connection between Firebase Dynamic Links and Analytics has been improved, so that if you use Dynamic link on your Facebook page, Analytics will detect the source as Facebook on the Analytics dashboard.
Unity Plugin for Firebase
An exciting announcement for game developers: Firebase now has a Unity3D plugin and an enhanced C++ SDK. (Most high-quality Android games are still built with C++.) This new feature also opens up some of the core Firebase functionalities such as AdMob, Analytics, Authentication, Realtime Database, Invites and Dynamic Links, Cloud Messaging and Remote Config for use in your game. The Firebase documentation has more information on how to add Firebase to your Unity setup.
Although it was not announced at the Firebase Dev Summit, you should also know that Google Play Services and Firebase will require API level 14 at a minimum starting from early 2017. The next release of these libraries (version 10.2.0) will increase the minimum supported API level from 9 to 14. So when building your app now, it is recommended to set your minimum SDK to be API level 14.
Conclusion
In this article, I told you about the new Firebase features that were announced at the Firebase Dev Summit in Berlin. Firebase has been working to make it easier for developers to code awesome apps, by taking care of the infrastructure and back-end for them. With these additional new features, the developer's job will be easier and faster.
Meanwhile, check out some of our other courses and tutorials on mobile development!
Variables in Swift are a fundamental and powerful language concept. Although they seem simple, they include a lot of functionality, and there are also some common pitfalls you will encounter when doing Swift programming.
In this short video tutorial from my course on creating iOS apps with Swift 3, I'll explain variables, constants, and optionals, with a special emphasis on the Swift type system.
Create an iOS App With Swift 3: Variables, Constants, and Optionals
Variables in Swift 3
Swift has some features that are very powerful and handy when it comes to variables. Let's start with a brand new playground.
As you can see, there already is a variable assignment on the screen, which was created by the template. It has the var keyword in front of it, followed by a variable name and the assignment—here, "Hello, playground". So far, so good.
What you don't see in this line of code is a type assignment. It's not necessary. Let's create a new variable called int and give it the value 8:
var int = 8
Okay, now let us change the str variable to be the value 4. Immediately, the compiler complains that you're trying to set a value of type int to be of type String.
How does it know about this?
It is inferred. Despite the way it looks, Swift is a statically typed language, which means every variable has a type. But unlike most other languages, it can infer the type when it gets assigned a value during definition. For our case, this means since the str variable was given a string, it automatically received the type String.
The same for the int variable. This one we can set to 4 because it is an integer.
Sometimes, you want to explicitly specify the type of variable. Of course, this is possible also. Let's create a variable double, and set it to 4.
We already know that it will be initialized to an integer, despite the name. So when we try to set it to 4.5, this will fail. To make sure it will be a double nonetheless, we have to set it by using a colon after the variable name, followed by the type, in upper case, Double.
Constants in Swift 3
Okay, now on to constants. Those are the ones to use if you don't want to change the value you initially set.
The Swift compiler is very smart about that and warns you if you use a variable where you want a constant and vice versa. To define a constant, you will need the keyword let instead of var. In the code from before, if you change the double variable to a constant, the compiler will warn you about the change you're trying to make in the next line by setting it to 4.5.
A thing that was very funny when Swift first came out is the fact that it is fully Unicode compatible. This also means that variable names can be any character in Unicode—like if you want to set π to 3.14159. It even supports using emojis to name your variables and functions.
Optionals in Swift 3
The final major feature regarding variables in Swift is optionals.
Whenever you define a variable, you need to initialize it before you use it. If you don't, your program won't compile. Sometimes, however, your variable won't always have a value. For example, when you have a callback function that either returns the result of an operation or an error.
Null Pointers
There has always been the concept of null pointers in programming. In Swift, those are named nil. Those are initialized variables with a special value of nothing. If you want to allow a nil value for a variable in Swift, you have to explicitly say so and the variable becomes an optional. For example:
var myVariable : String?
print(myVariable)
An optional is defined by adding a question mark to the type. This immediately makes the print statement work, and it outputs nil.
Let's change my variable to be a double, and let's multiply it by 2. Although nil is allowed, you can't do much with it. This means we need a safeguard. Since nil checks are a very common problem in programming, the language designers of Swift have decided to give us a special way of dealing with it.
You might have learnt that variable assignment in an if statement is bad practice. For Swift, this is different. If you're doing if let myVariable = myVariable, it will automatically unwrap the optional for you and make it available in the if block for you if it isn't nil.
So let's initialize the variable with a value. In the block, it will multiply it by 2 and print it. But if we try to do the same outside the block, it will of course fail.
If you absolutely know that a variable has a value and you don't want to wrap it in a conditional, you can also forcefully unwrap it by using an exclamation point. This will unwrap it if there is a value, but if there isn't, it will fail very hard with a runtime exception. So if you're working with optionals a lot, definitely remember this special if statement.
Type Conversion
A very important thing when it comes to working with static let types is type conversion.
Let's say you have a double and want an integer. In Swift, every type comes with an initializer, even booleans or integers. The default types also have initializers for compatible types, so we can use the int initializer to convert our double.
To further elaborate on type casting, I need to introduce a new set of types, collections. I'm pretty sure you know what an array is, and of course they also are available in Swift. Let's create an array of integers:
let intArray = [1, 2, 3, 4]
You might be used to putting anything that comes to mind in an array and also mixing types. But in Swift, arrays are also statically typed against their values. This means if you want to add a string to your array of integers, Swift doesn't know what to do. let intArray = [1, 2, 3, 4, "String"] will give an error message.
So let's remove the string and add it in a separate line to the array. Now it shows the error message I wanted to show you.
This error comes from the type of the array, since it is inferred to be an array of integers. We can explicitly set it to this type by using square brackets around the type of the content. This is the most concise method of defining the array.
You could also use the type array and use angle brackets to define the type. This might look more familiar to you if you come from another language. Of course, there are some cases where you actually want to allow mixed types in an array. In a minute, I'm going to show you another data type where you will store the JSON response of a web server, which might contain numbers, booleans, or strings.
There is a special keyword in Swift that allows those types to be present, and it is called Any. This means this can be any type. Of course, the problem is that we're still in a statically typed language. Now the values are of type Any. If we want to add the first two integers together, it simply fails to do so because the Any type doesn't support the addition operator.
This means we have to use type casting to convert them to the correct type. We can use the as keyword to do so. And, of course, since it's not safe, we need to use the bang as well to force it, as there is no known conversion between Any and int. If we do this, though, we have to be very careful with the actual types. If we cast the wrong element to be an integer, it will fail at runtime with an exception.
Now, there's one important thing missing. That is dictionaries. If you come from another language, you might know them as maps or hashes.
They have keys that have values. If you want to define them explicitly, you will do similar to the array using square brackets but separate the key and value by a colon.
Defining a String key and an Any value would be a very common use case when parsing JSON data from the web.
Watch the Full Course
In the full course, Create iOS Apps With Swift 3, you will get a comprehensive guide to using Swift 3 to create iOS apps.
Whether you're new to iOS app development or are looking to make the switch from Objective-C, this course will get you started with Swift for app development. You'll learn about all the basic features of the language, from variables to classes. You'll also get an introduction to using Xcode for app development as you follow along and implement the course project: an interactive Fibonacci sequence viewer.
Variables in Swift are a fundamental and powerful language concept. Although they seem simple, they include a lot of functionality, and there are also some common pitfalls you will encounter when doing Swift programming.
In this short video tutorial from my course on creating iOS apps with Swift 3, I'll explain variables, constants, and optionals, with a special emphasis on the Swift type system.
Create an iOS App With Swift 3: Variables, Constants, and Optionals
Variables in Swift 3
Swift has some features that are very powerful and handy when it comes to variables. Let's start with a brand new playground.
As you can see, there already is a variable assignment on the screen, which was created by the template. It has the var keyword in front of it, followed by a variable name and the assignment—here, "Hello, playground". So far, so good.
What you don't see in this line of code is a type assignment. It's not necessary. Let's create a new variable called int and give it the value 8:
var int = 8
Okay, now let us change the str variable to be the value 4. Immediately, the compiler complains that you're trying to set a value of type int to be of type String.
How does it know about this?
It is inferred. Despite the way it looks, Swift is a statically typed language, which means every variable has a type. But unlike most other languages, it can infer the type when it gets assigned a value during definition. For our case, this means since the str variable was given a string, it automatically received the type String.
The same for the int variable. This one we can set to 4 because it is an integer.
Sometimes, you want to explicitly specify the type of variable. Of course, this is possible also. Let's create a variable double, and set it to 4.
We already know that it will be initialized to an integer, despite the name. So when we try to set it to 4.5, this will fail. To make sure it will be a double nonetheless, we have to set it by using a colon after the variable name, followed by the type, in upper case, Double.
Constants in Swift 3
Okay, now on to constants. Those are the ones to use if you don't want to change the value you initially set.
The Swift compiler is very smart about that and warns you if you use a variable where you want a constant and vice versa. To define a constant, you will need the keyword let instead of var. In the code from before, if you change the double variable to a constant, the compiler will warn you about the change you're trying to make in the next line by setting it to 4.5.
A thing that was very funny when Swift first came out is the fact that it is fully Unicode compatible. This also means that variable names can be any character in Unicode—like if you want to set π to 3.14159. It even supports using emojis to name your variables and functions.
Optionals in Swift 3
The final major feature regarding variables in Swift is optionals.
Whenever you define a variable, you need to initialize it before you use it. If you don't, your program won't compile. Sometimes, however, your variable won't always have a value. For example, when you have a callback function that either returns the result of an operation or an error.
Null Pointers
There has always been the concept of null pointers in programming. In Swift, those are named nil. Those are initialized variables with a special value of nothing. If you want to allow a nil value for a variable in Swift, you have to explicitly say so and the variable becomes an optional. For example:
var myVariable : String?
print(myVariable)
An optional is defined by adding a question mark to the type. This immediately makes the print statement work, and it outputs nil.
Let's change my variable to be a double, and let's multiply it by 2. Although nil is allowed, you can't do much with it. This means we need a safeguard. Since nil checks are a very common problem in programming, the language designers of Swift have decided to give us a special way of dealing with it.
You might have learnt that variable assignment in an if statement is bad practice. For Swift, this is different. If you're doing if let myVariable = myVariable, it will automatically unwrap the optional for you and make it available in the if block for you if it isn't nil.
So let's initialize the variable with a value. In the block, it will multiply it by 2 and print it. But if we try to do the same outside the block, it will of course fail.
If you absolutely know that a variable has a value and you don't want to wrap it in a conditional, you can also forcefully unwrap it by using an exclamation point. This will unwrap it if there is a value, but if there isn't, it will fail very hard with a runtime exception. So if you're working with optionals a lot, definitely remember this special if statement.
Type Conversion
A very important thing when it comes to working with static let types is type conversion.
Let's say you have a double and want an integer. In Swift, every type comes with an initializer, even booleans or integers. The default types also have initializers for compatible types, so we can use the int initializer to convert our double.
To further elaborate on type casting, I need to introduce a new set of types, collections. I'm pretty sure you know what an array is, and of course they also are available in Swift. Let's create an array of integers:
let intArray = [1, 2, 3, 4]
You might be used to putting anything that comes to mind in an array and also mixing types. But in Swift, arrays are also statically typed against their values. This means if you want to add a string to your array of integers, Swift doesn't know what to do. let intArray = [1, 2, 3, 4, "String"] will give an error message.
So let's remove the string and add it in a separate line to the array. Now it shows the error message I wanted to show you.
This error comes from the type of the array, since it is inferred to be an array of integers. We can explicitly set it to this type by using square brackets around the type of the content. This is the most concise method of defining the array.
You could also use the type array and use angle brackets to define the type. This might look more familiar to you if you come from another language. Of course, there are some cases where you actually want to allow mixed types in an array. In a minute, I'm going to show you another data type where you will store the JSON response of a web server, which might contain numbers, booleans, or strings.
There is a special keyword in Swift that allows those types to be present, and it is called Any. This means this can be any type. Of course, the problem is that we're still in a statically typed language. Now the values are of type Any. If we want to add the first two integers together, it simply fails to do so because the Any type doesn't support the addition operator.
This means we have to use type casting to convert them to the correct type. We can use the as keyword to do so. And, of course, since it's not safe, we need to use the bang as well to force it, as there is no known conversion between Any and int. If we do this, though, we have to be very careful with the actual types. If we cast the wrong element to be an integer, it will fail at runtime with an exception.
Now, there's one important thing missing. That is dictionaries. If you come from another language, you might know them as maps or hashes.
They have keys that have values. If you want to define them explicitly, you will do similar to the array using square brackets but separate the key and value by a colon.
Defining a String key and an Any value would be a very common use case when parsing JSON data from the web.
Watch the Full Course
In the full course, Create iOS Apps With Swift 3, you will get a comprehensive guide to using Swift 3 to create iOS apps.
Whether you're new to iOS app development or are looking to make the switch from Objective-C, this course will get you started with Swift for app development. You'll learn about all the basic features of the language, from variables to classes. You'll also get an introduction to using Xcode for app development as you follow along and implement the course project: an interactive Fibonacci sequence viewer.
Welcome back to this series, in which you're learn how to use React Native to create page layouts commonly used in mobile apps. The layouts you're creating won't be functional—instead, the main focus of this series is to get your hands dirty in laying out content in your React Native apps.
If you're new to laying out React Native apps or styling in general, check out my previous tutorial:
To follow along with this series, I challenge you to try recreating each screen by yourself first, before you read my step-by-step instructions in the tutorial. You won't really benefit much from this tutorial just by reading it! Try first before looking up the answers here. If you succeed in making it look like the original screen, compare your implementation to mine. Then decide for yourself which one is better!
In this final tutorial of the series, you'll create the following news feed page:
News feed layouts are used to present information in such a way that it can be easily scanned. Most of the time it's presented in a list format with the title, excerpt, and optionally a preview image that represents each news item.
Here are a couple of examples of this type of layout being used in the wild:
Project Setup
The first step, of course, is to set up a new React Native project:
react-native init react-native-common-screens
Once the project is set up, open the index.android.js file and replace the default code with the following:
import React, { Component } from 'react';
import {
AppRegistry
} from 'react-native';
import News from './src/pages/News';
export default class ReactNativeCommonScreens extends Component {
render() {
return (
<News />
);
}
}
AppRegistry.registerComponent('ReactNativeCommonScreens', () => ReactNativeCommonScreens);
Create a src/pages folder and create a News.js file inside it.
You'll also need the react-native-vector-icons package. This is specifically used for the back icon in the header.
npm install --save react-native-vector-icons
Open the android/app/build.gradle file and add a reference to the package:
dependencies {
//rest of the dependencies are here at the top
compile project(':react-native-vector-icons') //add this
}
Do the same with the android/settings.gradle file by adding the following at the bottom:
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
Open android/app/src/main/java/com/react-native-common-screens/MainApplication.java and import the package:
import java.util.Arrays;
import java.util.List;
import com.oblador.vectoricons.VectorIconsPackage; //add this
Lastly, initialize the package:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new VectorIconsPackage() //add this
);
}
Creating the News Page
Okay, now that you've tried to code the layout yourself (no cheating, right?) I'll show you how I built my implementation.
You must have noticed the trend by now. I've arranged these according to difficulty—or at least according to what I found difficult! So this final screen is basically the big boss among the other screens that you've created so far. Fret not, though, as I'll still be guiding you step by step.
You will need a few images for the preview image of each news item. I've added some images in the repo that you can use if you want.
Start by adding the boilerplate code:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
ScrollView,
Image
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import Button from '../components/Button';
import NewsItem from '../components/NewsItem';
This time there's a new component named NewsItem (src/components/NewsItem). As the name suggests, it is used for rendering each news item. We'll come back to it later, but first take a look at the constructor() function. Just like the gallery screen earlier, this uses the state to store the data source for the news items. The titles and summaries are from the New York Times, but the images are from Google Images (and are labeled for reuse by their respective owners).
constructor(props) {
super(props);
this.state = {
news_items: [
{
pretext: 'Gray Matter',
title: 'Art Makes You Smart',
summary: 'Museum visits increase test scores, generate social responsibility and increase appreciation of the arts by students.',
image: require('../images/pink.jpg'),
},
{
pretext: '',
title: 'Tension and Flaws Before Health Website Crash',
summary: 'Interviews and documents offer new details into how the rollout of President Obama\'s signature program turned into a major humiliation.',
image: require('../images/beach.jpg')
},
{
pretext: '',
title: '36 Hours in Charleston, S.C.',
summary: 'Crowds are thinner and temperatures are mild during winter in this..',
image: require('../images/rails.jpg')
},
]
};
}
The content is divided into three parts: the header, the instruction text, and the news items. The header is very similar to the header from the calendar screen earlier; the only difference is that instead of three, there are only two visible elements. (If you want a refresher on how the calendar screen was made, go ahead and read over that tutorial.)
I say "visible" because there are actually three elements—the last one is just hidden! This allows for easy centering of the text in the middle. If you just have two elements in the header, it's tricky to figure out how to divide space between the two elements and still have the middle one appear centered. But if you have three elements, each one can have the same flex value, and you can just use textAlign to position text or alignItems to position View components.
Next up is the code for the NewsItem component. Start by adding the boilerplate React component code. As you've seen earlier, this component accepts the key, index, and news as its props. You only really need the index and news. key is just React Native's way of uniquely identifying each row in a list. You need to supply it every time you use Array.map for rendering; otherwise, it will complain.
When you use functional components, the props are passed as a single argument. Below, the individual props are extracted using destructuring assignment, so { news, index } basically extracts the news and index properties from the props. From there you can get the number to be rendered.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image
} from 'react-native';
import Button from './Button';
const NewsItem = ({ news, index }) => {
let number = (index + 1).toString();
return (
...
);
}
If you look at the screenshot from earlier, you can see that each news item can be divided into two groups: one that displays the news text (number, title, and the excerpt), and one that displays the feature image.
That solves the problem with the feature image since it's just one element. But for the news text, you still have to divide it further. As you may have noticed, the number is in the same position even if the title has a pretext (e.g. "Gray Matter"). The pretext also has a different styling from the title and the number.
Using this knowledge, you can deduce that the number, pretext, and title shouldn't be lumped together in a single container. Furthermore, the pretext, title, and excerpt look as if they're vertically stacked so you can put them inside a single container. Only the number should be brought out. With that, you'll arrive with the following markup:
I'll no longer be walking you through what each line of code does since it basically applies the same concepts you've learned in the previous tutorials in this series. Here's what the page will look like once the above styles are applied:
Next, add the styles for each news item. Each news_item has a flexDirection of row so that the news text and the featured image are all on a single line. news_text occupies two-thirds of the available space, while news_photo occupies the remaining space.
Next, you need to add the styling to fix the issue with the text overlapping with the preview image. You can do that by assigning a flex value to the children of the news_text. A flex value has already been assigned to news_text, but since a View has been used inside it, you also need to assign a flex value to those so that they won't go over the bounds of their parent View.
We'll assign a flex value of 0.5 to the number, while text_container will have a value of 3. With these values, the text_container will occupy six times as much space as the number.
That's it! In this final part of this series, you learned how to implement the layout commonly used in news pages. This tutorial brought together all the things that you've learned in the previous parts of the series. You've used both flexDirection: 'row' and flexDirection: 'column' to complete the styles for each news item. You also used your knowledge in aligning images for the preview image.
If you have tried to implement these layouts on your own, failed, and then tried again, you should already have enough skill to implement any kind of layout. You can apply the things you learned in here to implement even the complex layouts that you commonly see in popular apps. If you want more practice, try recreating the layouts you see in popular apps such as Facebook or YouTube.
How did my solution compare to your own? Let us know in the discussion forum below. And in the meantime, check out some of our other tutorials on React Native and Flexbox.
CSS, despite its relatively low perceived skill ceiling, always seems to have a killer feature up its sleeve. Remember how media queries made responsive...
React Native, created by Facebook, lets you write native mobile apps in modern JavaScript. React Native apps will be transformed into native views specific...
Are you looking to improve your flexbox knowledge and at the same time learn how to build easily an attractive and unique layout? If so, be sure to read this...
Animations can breath life into your app and make your UIs more intuitive. In this tutorial, you'll learn how to implement different kinds of animations in...
Are you a hybrid app developer wanting to include face detection into your app, but you don't have any idea where to start? As a start, you could read An...
In this tutorial, you're going to learn how to implement animations that are commonly used in mobile apps. Specifically, you're going to learn how to implement animations that:
Provide visual feedback: for example, when a user presses a button, you want to use animations to show the user that the button is indeed being pressed.
Show the current system status: when performing a process that doesn't finish instantly (e.g. when uploading a photo or sending an email), you want to show an animation so the user has an idea how long the process will take.
Visually connect transition states: when a user presses a button to bring something to the front of the screen, this transition should be animated so the user knows where the element originated.
Grab the user's attention: when there's an important notification, you can use animations to grab the user's attention.
This tutorial is a sequel to my Animate Your React Native App post. So if you're new to animations in React Native, be sure to check that out first, because some of the concepts that will be used in this tutorial are explained in more detail there.
Also, if you want to follow along, you can find the full source code used in this tutorial in its GitHub repo.
What We're Building
We're going to build an app which implements each of the different types of animation that I mentioned earlier. Specifically, we're going to create the following pages, each of which will implement animations for a different purpose.
News Page: uses gestures to provide visual feedback and show current system status.
Buttons Page: uses buttons to provide visual feedback and show current system status.
Progress Page: uses a progress bar to show current system status.
Expand Page: visually connects transition states using expanding and shrinking motions.
AttentionSeeker Page: uses eye-catching movements to grab the user's attention.
If you want to see a preview of each of the animations, check out this Imgur album.
Setting Up the Project
Start by creating a new React Native project:
react-native init RNPracticalAnimations
Once the project is created, navigate inside the newly created folder, open the package.json file, and add the following to dependencies:
Execute npm install to install those two packages. react-native-animatable is used to easily implement animations, and react-native-vector-icons is used to render icons for the expand page later on. If you don't want to use icons, you can just stick with using the Text component. Otherwise, follow the installation instructions of react-native-vector-icons on their GitHub page.
Building the App
Open the index.android.js file or index.ios.js file and replace the existing contents with the following:
import React, { Component } from 'react';
import {
AppRegistry
} from 'react-native';
import NewsPage from './src/pages/NewsPage';
import ButtonsPage from './src/pages/ButtonsPage';
import ProgressPage from './src/pages/ProgressPage';
import ExpandPage from './src/pages/ExpandPage';
import AttentionSeekerPage from './src/pages/AttentionSeekerPage';
class RNPracticalAnimation extends Component {
render() {
return (
<NewsPage />
);
}
}
AppRegistry.registerComponent('RNPracticalAnimation', () => RNPracticalAnimation);
Once that's done, be sure to create the corresponding files so you don't get any errors. All the files that we will be working on are stored under the src directory. Inside that directory are the following folders:
components: reusable components that will be used by other components or pages.
img: images that will be used throughout the app. You can get the images from the GitHub repo.
pages: the pages of the app.
News Page
Let's start with the News page.
First, add the components that we'll be using:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated,
Easing,
ScrollView,
RefreshControl
} from 'react-native';
import NewsItem from '../components/NewsItem';
You should already be familiar with most of these, except for RefreshControl and the custom NewsItem component, which we'll be creating later. RefreshControl is used to add a "pull to refresh" functionality inside a ScrollView or ListView component. So it's actually the one that will handle the swipe down gesture and animation for us. No need to implement our own. As you gain more experience in using React Native, you'll notice that animations are actually built in to some components, and there's no need to use the Animated class to implement your own.
Create the component that will house the whole page:
export default class NewsPage extends Component {
...
}
Inside the constructor, initialize an animated value for storing the current opacity (opacityValue) of the news items. We want the news items to have less opacity while the news items are being refreshed. This gives the user an idea that they can't interact with the whole page while the news items are being refreshed. is_news_refreshing is used as a switch to indicate whether the news items are currently being refreshed or not.
Inside the render() function, define how the opacity value will change. Here, the outputRange is [1, 0, 1], which means that it will start at full opacity, then go to zero opacity, and then back to full opacity again. As defined inside the opacity() function, this transition will be done over the course of 3,500 milliseconds (3.5 seconds).
The <RefreshControl> component is added to the <ScrollView>. This calls the refreshNews() function whenever the user swipes down while they're at the top of the list (when scrollY is 0). You can add the colors prop to customize the color of the refresh animation.
The refreshNews() function calls the opacity() function and updates the value of is_news_refreshing to true. This lets the <RefreshControl> component know that the refresh animation should already be shown. After that, use the setTimeout() function to update the value of is_news_refreshing back to false after 3,500 milliseconds (3.5 seconds). This will hide the refresh animation from view. By that time, the opacity animation should also be done since we set the same value for the duration in the opacity function earlier.
renderNewsItems() takes the array of news items that we declared earlier inside the constructor() and renders each of them using the <NewsItem> component.
The NewsItem component (src/components/NewsItem.js) renders the title and the website of the news item and wraps them inside the <Button> component so that they can be interacted with.
The Button component (src/components/Button.js) uses the TouchableHighlight component to create a button. The underlayColor props is used to specify the color of the underlay when the button is pressed. This is React Native's built-in way of providing visual feedback; later on, in the Buttons Page section, we'll take a look at other ways buttons can provide visual feedback.
The buttons page (src/pages/ButtonsPage.js) shows three kinds of buttons: the commonly used button which gets highlighted, a button which becomes slightly larger, and a button which shows the current state of an operation. Start by adding the necessary components:
import React, { Component } from 'react';
import {
StyleSheet,
View
} from 'react-native';
import Button from '../components/Button';
import ScalingButton from '../components/ScalingButton';
import StatefulButton from '../components/StatefulButton';
Earlier, you saw how the Button component works, so we'll just focus on the other two buttons.
Scaling Button Component
First, let's take a look at the scaling button (src/components/ScalingButton.js). Unlike the button that we used earlier, this uses the built-in TouchableWithoutFeedback component to create a button. Earlier, we used the TouchableHighlight component, which comes with all the bells and whistles for something to be considered a button. You can think of TouchableWithoutFeedback as a bare-bones button in which you have to specify everything that it needs to do when a user taps on it. This is perfect for our use case because we don't have to worry about default button behavior getting in the way of the animation that we want to implement.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
Animated,
Easing,
TouchableWithoutFeedback
} from 'react-native';
Just like the Button component, this will be a functional type of component since we don't really need to work with the state.
const ScalingButton = (props) => {
...
}
Inside the component, create an animated value that will store the current button scale.
var scaleValue = new Animated.Value(0);
Add the function that will start the scale animation. We don't want the app to appear slow, so make the duration as low as possible but also high enough so the user can perceive what's happening. 300 milliseconds is a good starting point, but feel free to play around with the value.
Define how the button will scale (outputRange) depending on the current value (inputRange). We don't want it to become too big so we stick with 1.1 as the highest value. This means it will be 0.1 bigger than its original size halfway through (0.5) the whole animation.
Next is the stateful button (src/components/StatefulButton.js). When pressed, this button will change its background color and show a loading image until the operation that it's performing is done.
The loading image that we'll be using is an animated gif. By default, React Native on Android doesn't support animated gifs. To make it work, you have to edit the android/app/build.gradle file and add compile 'com.facebook.fresco:animated-gif:0.12.0' under the dependencies like so:
dependencies {
//default dependencies here
compile 'com.facebook.fresco:animated-gif:0.12.0'
}
If you're on iOS, animated gifs should work by default.
Going back to the stateful button component, just like the scaling button, this uses the TouchableWithoutFeedback component to create the button since it will also implement its own animation.
import React, { Component } from 'react';
import {
StyleSheet,
View,
Image,
Text,
TouchableWithoutFeedback,
Animated
} from 'react-native';
Unlike the scaling button, this component will be a full-fledged class-based component since it manages its own state.
Inside the constructor(), create an animated value for storing the current background color. After that, initialize the state that acts as a switch for storing the current status of the button. By default, this is set to false. Once the user taps on the button, it will be updated to true and will only be set to false again once the imaginary process is done executing.
Next, wrap everything inside the TouchableWithoutFeedback component, and inside the <Animated.View> is where the animated background color is applied. We also render the loader image if the current value of is_loading is true. The button label also changes based on this value.
The changeColor() function is responsible for updating the state and animating the background color of the button. Here we're assuming that the process will take 3,000 milliseconds (3 seconds). But in a real-world scenario, you can't always know how long a process would take. What you can do is to have the animation execute for a shorter period of time and then call the changeColor() function recursively until the process is done.
The Progress page (src/pages/ProgressPage.js) shows a progress animation to the user during a long-running process. We will implement our own instead of using the built-in components because React Native doesn't have a unified way of implementing a progress bar animation yet. If you're interested, here are links to the two built-in progress bar components:
To build our Progress page, start by importing the components that we need:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated,
Dimensions
} from 'react-native';
We're using Dimensions to get the device width. From that, we can calculate the width available for the progress bar. We'll do so by subtracting the sum of the left and right paddings that we will add to the container, and also the left and right borders that we will add to the progress bar container.
var { width } = Dimensions.get('window');
var available_width = width - 40 - 12;
For the above formula to make sense, let's skip right to the styles:
The container has a padding of 20 on each side—thus we subtract 40 from the available_width. The progress_container has a border of 6 on each side, so we just double that again and subtract 12 from the progress bar width.
Create the component, and inside the constructor create the animated value for storing the current animation values for the progress bar.
I said "values" because this time we're going to use this single animated value to animate both the width and the background color of the progress bar. You'll see this in action later on.
Aside from that, you also need to initialize the current progress in the state.
Inside the render() function, the progress_container acts as the container for the progress bar, and the <Animated.View> inside it is the actual progress bar whose width and background color will change depending on the current progress. Below it, we're also rendering the current progress in text form (0% to 100%).
The styles for the progress bar are returned by the getProgressStyles() function. Here we're using the animated value from earlier to calculate the width and background color. This is done instead of creating a separate animated value for each animation because we're interpolating the same value anyway. If we used two separate values, we would need to have two animations in parallel, which is less efficient.
The animation is immediately executed once the component is mounted. Start by setting the initial progress value, and then add a listener to the current progress value. This allows us to update the state every time the progress value changes. We're using parseInt(), so the progress value is converted to a whole number. After that, we start the animation with a duration of 7,000 milliseconds (7 seconds). Once it's done, we change the progress text to done!
The expand page (src/pages/ExpandPage.js) shows how to visually connect transition states using expanding and shrinking motions. It's important to show the user how a specific element came to be. It answers the questions of where the element came from and what its role is in the current context. As always, start by importing the things that we need:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import ScalingButton from '../components/ScalingButton';
Inside the constructor(), create an animated value that will store the current y-position of the menu. The idea is to have a big box that's enough to contain all the menu items.
Initially, the box will have a negative value for the bottom position. This means that only the tip of the whole box will be shown by default. Once the user taps on the menu, the whole box will look as if it's expanded, when in reality we're only changing the bottom position so that everything is shown.
You might be wondering why we use this approach instead of just scaling the box to accommodate all its children. That's because we only need to scale the height attribute. Think what happens to images when you just adjust their height or width alone—they look stretched. The same thing would happen to the elements inside the box.
Going back to the constructor(), we also add a state flag that indicates whether the menu is currently expanded or not. We need this because we need to hide the button for expanding the menu if the menu is already expanded.
Inside the render() function, specify how the bottom position will be translated. The inputRange is 0 and 1, and the outputRange is 0 and -300. So if the y_translate has a value of 0, nothing will happen because the outputRange equivalent is 0. But if the value becomes 1, the menu's bottom position is translated to -300 from its original position.
Take note of the negative sign, because if it's just 300, the box will go down even further. If it's a negative number, the opposite will happen.
Notice the footer_menu style. Its total height is set to 350, and the bottom position is -300, which means that only the top 50 is shown by default. When the translate animation is executed to expand the menu, the bottom position ends up with a value of 0. Why? Because if you still remember the rules when subtracting negative numbers, two minus signs become a positive. So (-300) - (-300) becomes (-300) + 300.
We all know what happens when adding positive and negative numbers: they cancel each other out. So the bottom position ends up becoming 0, and the whole of the menu is displayed.
Going back to the render() function, we have the main content (body) and the footer menu, which is the one that will be expanded and shrunk. The translateY transform is used to translate its position in the Y-axis. Because the whole container has flex: 10 and the body is also flex: 10, the starting point is actually at the very bottom of the screen.
Inside the <Animated.View> are the tip_menu and the full menu. If the menu is expanded, we don't want the tip menu to be shown, so we only render it if menu_expanded is set to false.
On the other hand, we only want to display the full menu if menu_expanded is set to true. Each of the buttons will shrink the menu back to its original position.
When opening the menu, the state needs to be updated first so that the hidden menus will be rendered. Only once that's done can the translate animation be executed. This uses Animated.spring as opposed to Animated.timing to add a bit of playfulness to the animation. The higher the value you supply to the friction, the less bounce there will be. Remember not to overdo your animations because instead of helping the user, they can end up being an annoyance.
Last but not the least is the attentionseeker page (src/pages/AttentionSeekerPage.js). I know that this tutorial is already getting quite long, so to make things shorter, let's use the react-native-animatable package to implement the animations for this page.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import ScalingButton from '../components/ScalingButton';
Create an array containing the type of animation and the background color to be used for each box:
The renderBoxes() function renders the animated boxes. This uses the starting index supplied as an argument to extract a specific part of the array and render them individually.
Here we're using the <Animatable.View> component instead of <Animated.View>. This accepts the animation and iterationCount as props. The animation specifies the type of animation you want to perform, and the iterationCount specifies how many times you want to execute the animation. In this case, we just want to bug the user until they press on the box.
In this tutorial, you've learned how to implement some animations commonly used in mobile apps. Specifically, you've learned how to implement animations that provide visual feedback, show the current system status, visually connect transition states, and grab the user's attention.
As always, there's still a lot more to learn when it comes to animations. For example, we still haven't touched the following areas:
How to perform animations on specific user gestures such as dragging, flicking, pinching, and spreading. For example, when the user uses the spread gesture, you should use a scale animation to show how the element involved becomes bigger.
How to animate the transition of multiple elements from one state to another. For example, when showing a list of photos, you may want to perform a stagger animation to delay the showing of all the photos.
Intro animation for first-time users of the app. A video could be used as an alternative, but this is also a good place to implement animations.
Maybe I'll cover some of those topics in a future tutorial. In the meantime, check out some of our other courses and tutorials on React Native!
React Native, created by Facebook, lets you write native mobile apps in modern JavaScript. React Native apps will be transformed into native views specific...
Animations can breath life into your app and make your UIs more intuitive. In this tutorial, you'll learn how to implement different kinds of animations in...
Facebook's React Native is a powerful open source framework that allows you to quickly and effortlessly create native Android and iOS apps using just...
In this tutorial, you're going to learn how to implement animations that are commonly used in mobile apps. Specifically, you're going to learn how to implement animations that:
Provide visual feedback: for example, when a user presses a button, you want to use animations to show the user that the button is indeed being pressed.
Show the current system status: when performing a process that doesn't finish instantly (e.g. when uploading a photo or sending an email), you want to show an animation so the user has an idea how long the process will take.
Visually connect transition states: when a user presses a button to bring something to the front of the screen, this transition should be animated so the user knows where the element originated.
Grab the user's attention: when there's an important notification, you can use animations to grab the user's attention.
This tutorial is a sequel to my Animate Your React Native App post. So if you're new to animations in React Native, be sure to check that out first, because some of the concepts that will be used in this tutorial are explained in more detail there.
Also, if you want to follow along, you can find the full source code used in this tutorial in its GitHub repo.
What We're Building
We're going to build an app which implements each of the different types of animation that I mentioned earlier. Specifically, we're going to create the following pages, each of which will implement animations for a different purpose.
News Page: uses gestures to provide visual feedback and show current system status.
Buttons Page: uses buttons to provide visual feedback and show current system status.
Progress Page: uses a progress bar to show current system status.
Expand Page: visually connects transition states using expanding and shrinking motions.
AttentionSeeker Page: uses eye-catching movements to grab the user's attention.
If you want to see a preview of each of the animations, check out this Imgur album.
Setting Up the Project
Start by creating a new React Native project:
react-native init RNPracticalAnimations
Once the project is created, navigate inside the newly created folder, open the package.json file, and add the following to dependencies:
Execute npm install to install those two packages. react-native-animatable is used to easily implement animations, and react-native-vector-icons is used to render icons for the expand page later on. If you don't want to use icons, you can just stick with using the Text component. Otherwise, follow the installation instructions of react-native-vector-icons on their GitHub page.
Building the App
Open the index.android.js file or index.ios.js file and replace the existing contents with the following:
import React, { Component } from 'react';
import {
AppRegistry
} from 'react-native';
import NewsPage from './src/pages/NewsPage';
import ButtonsPage from './src/pages/ButtonsPage';
import ProgressPage from './src/pages/ProgressPage';
import ExpandPage from './src/pages/ExpandPage';
import AttentionSeekerPage from './src/pages/AttentionSeekerPage';
class RNPracticalAnimation extends Component {
render() {
return (
<NewsPage />
);
}
}
AppRegistry.registerComponent('RNPracticalAnimation', () => RNPracticalAnimation);
Once that's done, be sure to create the corresponding files so you don't get any errors. All the files that we will be working on are stored under the src directory. Inside that directory are the following folders:
components: reusable components that will be used by other components or pages.
img: images that will be used throughout the app. You can get the images from the GitHub repo.
pages: the pages of the app.
News Page
Let's start with the News page.
First, add the components that we'll be using:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated,
Easing,
ScrollView,
RefreshControl
} from 'react-native';
import NewsItem from '../components/NewsItem';
You should already be familiar with most of these, except for RefreshControl and the custom NewsItem component, which we'll be creating later. RefreshControl is used to add a "pull to refresh" functionality inside a ScrollView or ListView component. So it's actually the one that will handle the swipe down gesture and animation for us. No need to implement our own. As you gain more experience in using React Native, you'll notice that animations are actually built in to some components, and there's no need to use the Animated class to implement your own.
Create the component that will house the whole page:
export default class NewsPage extends Component {
...
}
Inside the constructor, initialize an animated value for storing the current opacity (opacityValue) of the news items. We want the news items to have less opacity while the news items are being refreshed. This gives the user an idea that they can't interact with the whole page while the news items are being refreshed. is_news_refreshing is used as a switch to indicate whether the news items are currently being refreshed or not.
Inside the render() function, define how the opacity value will change. Here, the outputRange is [1, 0, 1], which means that it will start at full opacity, then go to zero opacity, and then back to full opacity again. As defined inside the opacity() function, this transition will be done over the course of 3,500 milliseconds (3.5 seconds).
The <RefreshControl> component is added to the <ScrollView>. This calls the refreshNews() function whenever the user swipes down while they're at the top of the list (when scrollY is 0). You can add the colors prop to customize the color of the refresh animation.
The refreshNews() function calls the opacity() function and updates the value of is_news_refreshing to true. This lets the <RefreshControl> component know that the refresh animation should already be shown. After that, use the setTimeout() function to update the value of is_news_refreshing back to false after 3,500 milliseconds (3.5 seconds). This will hide the refresh animation from view. By that time, the opacity animation should also be done since we set the same value for the duration in the opacity function earlier.
renderNewsItems() takes the array of news items that we declared earlier inside the constructor() and renders each of them using the <NewsItem> component.
The NewsItem component (src/components/NewsItem.js) renders the title and the website of the news item and wraps them inside the <Button> component so that they can be interacted with.
The Button component (src/components/Button.js) uses the TouchableHighlight component to create a button. The underlayColor props is used to specify the color of the underlay when the button is pressed. This is React Native's built-in way of providing visual feedback; later on, in the Buttons Page section, we'll take a look at other ways buttons can provide visual feedback.
The buttons page (src/pages/ButtonsPage.js) shows three kinds of buttons: the commonly used button which gets highlighted, a button which becomes slightly larger, and a button which shows the current state of an operation. Start by adding the necessary components:
import React, { Component } from 'react';
import {
StyleSheet,
View
} from 'react-native';
import Button from '../components/Button';
import ScalingButton from '../components/ScalingButton';
import StatefulButton from '../components/StatefulButton';
Earlier, you saw how the Button component works, so we'll just focus on the other two buttons.
Scaling Button Component
First, let's take a look at the scaling button (src/components/ScalingButton.js). Unlike the button that we used earlier, this uses the built-in TouchableWithoutFeedback component to create a button. Earlier, we used the TouchableHighlight component, which comes with all the bells and whistles for something to be considered a button. You can think of TouchableWithoutFeedback as a bare-bones button in which you have to specify everything that it needs to do when a user taps on it. This is perfect for our use case because we don't have to worry about default button behavior getting in the way of the animation that we want to implement.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
Animated,
Easing,
TouchableWithoutFeedback
} from 'react-native';
Just like the Button component, this will be a functional type of component since we don't really need to work with the state.
const ScalingButton = (props) => {
...
}
Inside the component, create an animated value that will store the current button scale.
var scaleValue = new Animated.Value(0);
Add the function that will start the scale animation. We don't want the app to appear slow, so make the duration as low as possible but also high enough so the user can perceive what's happening. 300 milliseconds is a good starting point, but feel free to play around with the value.
Define how the button will scale (outputRange) depending on the current value (inputRange). We don't want it to become too big so we stick with 1.1 as the highest value. This means it will be 0.1 bigger than its original size halfway through (0.5) the whole animation.
Next is the stateful button (src/components/StatefulButton.js). When pressed, this button will change its background color and show a loading image until the operation that it's performing is done.
The loading image that we'll be using is an animated gif. By default, React Native on Android doesn't support animated gifs. To make it work, you have to edit the android/app/build.gradle file and add compile 'com.facebook.fresco:animated-gif:0.12.0' under the dependencies like so:
dependencies {
//default dependencies here
compile 'com.facebook.fresco:animated-gif:0.12.0'
}
If you're on iOS, animated gifs should work by default.
Going back to the stateful button component, just like the scaling button, this uses the TouchableWithoutFeedback component to create the button since it will also implement its own animation.
import React, { Component } from 'react';
import {
StyleSheet,
View,
Image,
Text,
TouchableWithoutFeedback,
Animated
} from 'react-native';
Unlike the scaling button, this component will be a full-fledged class-based component since it manages its own state.
Inside the constructor(), create an animated value for storing the current background color. After that, initialize the state that acts as a switch for storing the current status of the button. By default, this is set to false. Once the user taps on the button, it will be updated to true and will only be set to false again once the imaginary process is done executing.
Next, wrap everything inside the TouchableWithoutFeedback component, and inside the <Animated.View> is where the animated background color is applied. We also render the loader image if the current value of is_loading is true. The button label also changes based on this value.
The changeColor() function is responsible for updating the state and animating the background color of the button. Here we're assuming that the process will take 3,000 milliseconds (3 seconds). But in a real-world scenario, you can't always know how long a process would take. What you can do is to have the animation execute for a shorter period of time and then call the changeColor() function recursively until the process is done.
The Progress page (src/pages/ProgressPage.js) shows a progress animation to the user during a long-running process. We will implement our own instead of using the built-in components because React Native doesn't have a unified way of implementing a progress bar animation yet. If you're interested, here are links to the two built-in progress bar components:
To build our Progress page, start by importing the components that we need:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated,
Dimensions
} from 'react-native';
We're using Dimensions to get the device width. From that, we can calculate the width available for the progress bar. We'll do so by subtracting the sum of the left and right paddings that we will add to the container, and also the left and right borders that we will add to the progress bar container.
var { width } = Dimensions.get('window');
var available_width = width - 40 - 12;
For the above formula to make sense, let's skip right to the styles:
The container has a padding of 20 on each side—thus we subtract 40 from the available_width. The progress_container has a border of 6 on each side, so we just double that again and subtract 12 from the progress bar width.
Create the component, and inside the constructor create the animated value for storing the current animation values for the progress bar.
I said "values" because this time we're going to use this single animated value to animate both the width and the background color of the progress bar. You'll see this in action later on.
Aside from that, you also need to initialize the current progress in the state.
Inside the render() function, the progress_container acts as the container for the progress bar, and the <Animated.View> inside it is the actual progress bar whose width and background color will change depending on the current progress. Below it, we're also rendering the current progress in text form (0% to 100%).
The styles for the progress bar are returned by the getProgressStyles() function. Here we're using the animated value from earlier to calculate the width and background color. This is done instead of creating a separate animated value for each animation because we're interpolating the same value anyway. If we used two separate values, we would need to have two animations in parallel, which is less efficient.
The animation is immediately executed once the component is mounted. Start by setting the initial progress value, and then add a listener to the current progress value. This allows us to update the state every time the progress value changes. We're using parseInt(), so the progress value is converted to a whole number. After that, we start the animation with a duration of 7,000 milliseconds (7 seconds). Once it's done, we change the progress text to done!
The expand page (src/pages/ExpandPage.js) shows how to visually connect transition states using expanding and shrinking motions. It's important to show the user how a specific element came to be. It answers the questions of where the element came from and what its role is in the current context. As always, start by importing the things that we need:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Animated
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import ScalingButton from '../components/ScalingButton';
Inside the constructor(), create an animated value that will store the current y-position of the menu. The idea is to have a big box that's enough to contain all the menu items.
Initially, the box will have a negative value for the bottom position. This means that only the tip of the whole box will be shown by default. Once the user taps on the menu, the whole box will look as if it's expanded, when in reality we're only changing the bottom position so that everything is shown.
You might be wondering why we use this approach instead of just scaling the box to accommodate all its children. That's because we only need to scale the height attribute. Think what happens to images when you just adjust their height or width alone—they look stretched. The same thing would happen to the elements inside the box.
Going back to the constructor(), we also add a state flag that indicates whether the menu is currently expanded or not. We need this because we need to hide the button for expanding the menu if the menu is already expanded.
Inside the render() function, specify how the bottom position will be translated. The inputRange is 0 and 1, and the outputRange is 0 and -300. So if the y_translate has a value of 0, nothing will happen because the outputRange equivalent is 0. But if the value becomes 1, the menu's bottom position is translated to -300 from its original position.
Take note of the negative sign, because if it's just 300, the box will go down even further. If it's a negative number, the opposite will happen.
Notice the footer_menu style. Its total height is set to 350, and the bottom position is -300, which means that only the top 50 is shown by default. When the translate animation is executed to expand the menu, the bottom position ends up with a value of 0. Why? Because if you still remember the rules when subtracting negative numbers, two minus signs become a positive. So (-300) - (-300) becomes (-300) + 300.
We all know what happens when adding positive and negative numbers: they cancel each other out. So the bottom position ends up becoming 0, and the whole of the menu is displayed.
Going back to the render() function, we have the main content (body) and the footer menu, which is the one that will be expanded and shrunk. The translateY transform is used to translate its position in the Y-axis. Because the whole container has flex: 10 and the body is also flex: 10, the starting point is actually at the very bottom of the screen.
Inside the <Animated.View> are the tip_menu and the full menu. If the menu is expanded, we don't want the tip menu to be shown, so we only render it if menu_expanded is set to false.
On the other hand, we only want to display the full menu if menu_expanded is set to true. Each of the buttons will shrink the menu back to its original position.
When opening the menu, the state needs to be updated first so that the hidden menus will be rendered. Only once that's done can the translate animation be executed. This uses Animated.spring as opposed to Animated.timing to add a bit of playfulness to the animation. The higher the value you supply to the friction, the less bounce there will be. Remember not to overdo your animations because instead of helping the user, they can end up being an annoyance.
Last but not the least is the attentionseeker page (src/pages/AttentionSeekerPage.js). I know that this tutorial is already getting quite long, so to make things shorter, let's use the react-native-animatable package to implement the animations for this page.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import ScalingButton from '../components/ScalingButton';
Create an array containing the type of animation and the background color to be used for each box:
The renderBoxes() function renders the animated boxes. This uses the starting index supplied as an argument to extract a specific part of the array and render them individually.
Here we're using the <Animatable.View> component instead of <Animated.View>. This accepts the animation and iterationCount as props. The animation specifies the type of animation you want to perform, and the iterationCount specifies how many times you want to execute the animation. In this case, we just want to bug the user until they press on the box.
In this tutorial, you've learned how to implement some animations commonly used in mobile apps. Specifically, you've learned how to implement animations that provide visual feedback, show the current system status, visually connect transition states, and grab the user's attention.
As always, there's still a lot more to learn when it comes to animations. For example, we still haven't touched the following areas:
How to perform animations on specific user gestures such as dragging, flicking, pinching, and spreading. For example, when the user uses the spread gesture, you should use a scale animation to show how the element involved becomes bigger.
How to animate the transition of multiple elements from one state to another. For example, when showing a list of photos, you may want to perform a stagger animation to delay the showing of all the photos.
Intro animation for first-time users of the app. A video could be used as an alternative, but this is also a good place to implement animations.
Maybe I'll cover some of those topics in a future tutorial. In the meantime, check out some of our other courses and tutorials on React Native!
React Native, created by Facebook, lets you write native mobile apps in modern JavaScript. React Native apps will be transformed into native views specific...
Animations can breath life into your app and make your UIs more intuitive. In this tutorial, you'll learn how to implement different kinds of animations in...
Facebook's React Native is a powerful open source framework that allows you to quickly and effortlessly create native Android and iOS apps using just...
High replay value is one of the defining characteristics of a great game. Even games with very simple plots can become successful on Google Play so long as they have a high replay value. If you are an avid gamer, you probably already know what replay value is. If you don't, you can think of it as the likelihood that a user is going to play a game again even after achieving its primary objective.
By using the events and quests APIs, which are a subset of the Google Play games services APIs, you can dramatically increase the replay values of your games, not to mention make them more challenging and fun. In this tutorial, I'll show you how to make the most of both the APIs.
Before you proceed, I suggest you read my introductory tutorial about Google Play games services, which shows you how to use the services in an Android Studio project.
Anything that happens in a game can be considered an event. By logging enough events using the events API, you can closely analyze the behaviors of your users. You can infer details such as how far the users are able to go in your game, how many enemies they kill, and how many in-game resources they collect. With such details at hand, you'll be able to easily refine your game to make it more enjoyable.
The events API, however, is rarely used alone. Most developers use it along with the quests API to create quests. A quest, as its name suggests, is a secondary objective the users can achieve to gain some reward. For example, if you are creating a game where the user is trying to save a princess, you can add a quest to it where the user must find at least 100 rings for her.
If you haven't guessed it already, events are used to define the completion criteria of quests. In the above example, finding a ring would be an event that must occur 100 times for the quest to be marked as complete.
Although quests share some similarities with achievements, there are a few important differences between the two:
You don't have to write any code to add a new quest to your game, provided the events it depends on are already a part of the game.
Quests are time-bound. For example, you can schedule a new quest to start a week before Christmas and challenge users to complete it before Christmas Eve.
A user can complete a quest only after choosing to participate in it.
With lots of interesting quests, some of which are scheduled to repeat every week or month, you can effortlessly get users to play your game multiple times.
2. Creating an Event
Log in to the Play developer console and open the Game Services screen by clicking on the gamepad icon.
Next, pick the game you want to add events to and open the Events section.
Press the Add event button to start creating an event. In the form that pops up, give a meaningful name to the event. Continuing with the example of the previous step, I'll call the event Collect Ring.
Once you press the Save button, you'll be able to see the ID of the event. To be able to use the event in your Android Studio project, you must add the ID as a new <string> tag in the games-ids.xml file.
Creating a quest is slightly more involved. Start by going to the Quests section and pressing the Add quest button. Give the quest an attractive name and an easy-to-understand description. Both are very important because they will be read by the users. A quest that doesn't look interesting is unlikely to see many participants.
Next, scroll down to the Completion criteria section. In the Find an event field, type in the ID of the event you created earlier. In the next input field, you must specify how many times the event must occur for the quest to be completed.
In the Schedule section, specify the Start date and time of the quest. To be able to start working with the quest immediately, you can choose today's date.
You must also specify the duration of the quest by typing in a value in the Number of days field. Optionally, you can choose to notify quest participants when they are almost out of time.
A quest must have a reward—why else would a user choose to participate in it? You can specify what the reward is by uploading a reward file, which can be a file of any format. Most developers choose to use the JSON format. Here's a sample reward file:
{
points: 3000,
max_lives: 15
}
It is worth noting that the contents of the reward file are not important to the Play games services APIs. It is your responsibility to parse and use them in your game.
In the Reward data section, press the Browse button and upload the reward file you created.
Finally, press Save to generate an ID for the quest. Optionally, you can copy the ID and add it to your Android Studio project's games-ids.xml file as another <string> tag.
The quests API offers an activity that can display all the quests that are available in your game. The activity also allows users to join quests.
To open the quests activity, you must create an intent for it using the getQuestsIntent() method of the Games.Quests class. As its arguments, it expects a GoogleApiClient object and an int array specifying the types of quests you want to display. Here are some popular values for the types of quests:
Quests.SELECT_OPEN, a quest a user can participate in right away.
Quests.SELECT_UPCOMING, a quest that is yet to start.
Quests.SELECT_COMPLETED, a quest the user has completed already.
Quests.SELECT_ACCEPTED, a quest the user is currently participating in.
After creating the Intent object, you can pass it to the startActivityForResult() method to display the quests activity.
The following code shows you how to open the quests activity and display four types of quests:
The user becomes a participant of the quest by pressing the Accept button. During a quest, the users can return to the quests UI to see how much of the quest is complete.
5. Using the Events API
The events API allows you to easily manage events in your game. To change the value of an event, you can use the increment() method of the Games.Events class. As its arguments, it expects a GoogleApiClient object, the name of the event, and a number specifying how much the value of the event should be increased.
The following code increments the value of the event_collect_ring event by 1:
To fetch the current values of events, you must use the load() method. Because the value is fetched from Google's servers asynchronously, the return value of the method is a PendingResult object. By adding a ResultCallback object to it, you can be notified when the result is available.
Inside the onResult() method of the ResultCallback interface, you must call the getEvents() method of the Events.LoadEventsResult object, which returns an EventBuffer. Once you find the desired Event in the buffer, you can call its getValue() method to get its current value.
The following code shows you how to fetch the value of the event_collect_ring event:
PendingResult<Events.LoadEventsResult> results =
Games.Events.load(apiClient, true);
results.setResultCallback(
new ResultCallback<Events.LoadEventsResult>() {
@Override
public void onResult(@NonNull Events.LoadEventsResult
loadEventsResult) {
// Fetch all events of the game
EventBuffer events = loadEventsResult.getEvents();
// Loop through all the events
for(int i = 0; i < events.getCount(); i++) {
Event currentEvent = events.get(i);
// Check if current event is the desired event
// and print its value
if(currentEvent.getEventId().equals(getString(
R.string.event_collect_ring)))
Log.d(TAG, "You have now collected " +
currentEvent.getValue() + " rings");
}
}
}
);
6. Detecting Quest Completion
When a user completes a quest on time, your game must be able to reward the user using the rewards file you uploaded in the Play developer console. To detect quest completion, you must create a QuestUpdateListener object and register it with the quests API using the registerQuestUpdateListener() method of the Games.Quests class.
Inside the onQuestCompleted() method of the QuestUpdateListener interface, you must call the claim() method to claim the reward of the quest. You must pass a GoogleApiClient object, the quest ID, and the current milestone's ID to the method.
After the claim, you can fetch the reward file as a byte array by calling the getCompletionRewardData() method. Because our reward data is just a JSON file, you can pass the byte array to the constructor of the String class to convert it into a string.
Games.Quests.registerQuestUpdateListener(apiClient,
new QuestUpdateListener() {
@Override
public void onQuestCompleted(Quest quest) {
Games.Quests.claim(apiClient, quest.getQuestId(),
quest.getCurrentMilestone()
.getMilestoneId());
byte[] rewardData = quest.getCurrentMilestone()
.getCompletionRewardData();
String reward = new String(rewardData);
}
}
);
At this point, you can convert the string into a JSONObject instance, and read the values of the keys inside it. The following code shows you how to fetch the values of two keys called points and max_lives:
try {
JSONObject rewardObject = new JSONObject(reward);
int points = rewardObject.getInt("points");
int maxLives = rewardObject.getInt("max_lives");
Log.d(TAG, "You have now gained "
+ points + " points and "
+ maxLives + " lives");
} catch(Exception e) {
Log.e(TAG, "Couldn't parse JSON");
}
Note that the quests activity automatically updates itself when a quest has been completed. Here's what a completed quest looks like:
Conclusion
In this tutorial, you learned how to use the quests and events APIs to persuade users to play your game again and again. Note, however, that because these APIs have rate limits, you must try to avoid using them too often in your app. You can refer to the Play games services quality checklist page to learn about more restrictions and best practices.
To learn more about quests and events, you can refer to their official documentation. And in the meantime, check out some of our other posts on Firebase and Google Play Services!
If you are developing a game for the Android platform, you can make use of the Google Play games services APIs to quickly add common gaming features. In this...
Google has recently released the Awareness API, which allows developers to create apps that intelligently react to the user's real-world situation. In this...
Creating a back-end server requires a skill set that most independent app developers lack. Fortunately, there's Firebase, a cloud-based platform that...
The Firebase team announced some new features at the Firebase Dev summit this November in Berlin. In this article, I'll take you through some of the most...
A UIAlertController is used to display an alert message in an app. For example, if an error occurs, the alert can show a description and buttons to take further action. You can use alerts to make users log in or sign up, show the results of an action they made, or offer a few more settings options—for example when you have no room for extra buttons on a screen but you need users to be able to perform some more actions on a specific object in the app.
Since iOS 9, Apple has replaced UIAlertView with UIAlertController. You no longer have to add the UIAlertViewDelegate into your class and are now able to style your alert as you wish. You can customize the title and message fonts, change the background color, and add text fields.For the sake of this tutorial we have created a demo app with three buttons, and each one will fire a different customized alert. You can download it from the tutorial source repo on GitHub. Now let's see how easy it is to build these custom alerts!
Alert With a Text Field
The first alert we're going to build has a TextField attached where you can input anything you want from the iOS keyboard. In order to initialize a UIAlertController, you have to start with these three lines:
In the first line, we set a simple string as a title of the alert. In the second line is the message string that will be displayed right below the title. In the third line, the alert's type is set to .alert. (Another option is .actionSheet, but you can't customize an action sheet like you can an alert.)
In an alert controller, buttons are defined as UIAlertAction elements. So we're going to create a UIAlertAction, which will be the first button on the bottom-left side of our alert.
// Submit button
let submitAction = UIAlertAction(title: "Submit", style: .default, handler: { (action) -> Void in
// Get 1st TextField's text
let textField = alert.textFields![0]
print(textField.text!)
})
We've called this action submitAction, set its title to "Submit", given it the default style, and for its handler, printed the content of a text field. Since text fields in the alert have an index, we've selected the first one at position 0. Later on we'll see how to add multiple text fields to an alert.
Once you've tapped the Submit button in your alert, the Xcode console will print the text you've entered and dismiss the alert.
Let's create a button to just hide our alert:
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
As you can see, this action has no handler. That's because we want to dismiss the alert and perform no other actions. This button will show a red Cancel title because we've set its style as .destructive, which the Apple API will understand.
Before adding these two actions to the Alert, we have to initialize our text field:
// Add 1 textField and customize it
alert.addTextField { (textField: UITextField) in
textField.keyboardAppearance = .dark
textField.keyboardType = .default
textField.autocorrectionType = .default
textField.placeholder = "Type something here"
textField.clearButtonMode = .whileEditing
}
If you're familiar with UITextFields, you'll recognize these as standard attributes which set properties such as the keyboard appearance and type, autocorrection type, placeholder message, and clear button. (We've set the clear button to show up when you start typing something.)
Now, let's finish off our alert.
// Add action buttons and present the Alert
alert.addAction(submitAction)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
The UIAlertController doesn't handle arrays of actions, so we must add them one by one. Lastly, we present the alert as we would any other controller—with the present() function.
In our demo app, we've embedded all the code above into a Button, so if you run the app and tap it, you should see something like this:
If you type something in the empty text field and hit Submit, your Xcode console will print it out.
Alert With Three Text Fields
Now let's create a new alert with multiple Text Fields to create a login prompt. We'll start again with the three lines that initialize our alert:
We still have two Buttons, one to perform a login action and the cancel button:
// Login button
let loginAction = UIAlertAction(title: "Login", style: .default, handler: { (action) -> Void in
// Get TextFields text
let usernameTxt = alert.textFields![0]
let passwordTxt = alert.textFields![1]
let phoneTxt = alert.textFields![2]
print("USERNAME: \(usernameTxt.text!)\nPASSWORD: \(passwordTxt.text!)\nPHONE NO.: \(phoneTxt.text!)")
})
As you can see, our alert has three text fields. These are indexed by their position. We'll treat the top one as the user name, the middle one as the password, and the last one as a phone number.
Now add a Cancel button:
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
Next we're going to create and customize the username Text Field:
Since passwords must usually be hidden, we've set the isSecureTextEntry attribute on our Text Field. This command will replace characters that you type with dots, as password fields do on a website. We've also set the text color to red.
And the third text element, for the phone number field:
The keyboardType attribute is set as .numberPad here, so the app will display the numeric keyboard only. You may also notice that we've changed the font of this text field to American Typewriter in the last line of code.
We're almost done—we just need to add our actions and present the AlertController again:
// Add action buttons and present the Alert
alert.addAction(loginAction)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
Now, if you run the app and fire this alert, you will see something like this:
If you try typing something in the text fields, you'll see the custom styling we applied.
Alert With Four Buttons
For a final example, I'll show you an alert with four actions and some different styling.
Since we'll customize the title and message attributes of this alert later, our initialization code will have empty strings for now:
let alert = UIAlertController(title: "",
message: "",
preferredStyle: .alert)
Here's how we'll set up the font and size of the title and message fields:
// Change font of the title and message
let titleFont:[String : AnyObject] = [ NSFontAttributeName : UIFont(name: "AmericanTypewriter", size: 18)! ]
let messageFont:[String : AnyObject] = [ NSFontAttributeName : UIFont(name: "HelveticaNeue-Thin", size: 14)! ]
let attributedTitle = NSMutableAttributedString(string: "Multiple buttons", attributes: titleFont)
let attributedMessage = NSMutableAttributedString(string: "Select an Action", attributes: messageFont)
alert.setValue(attributedTitle, forKey: "attributedTitle")
alert.setValue(attributedMessage, forKey: "attributedMessage")
In the first two lines we set the font name and size as a Dictionary of NSFontAttributeName. Please note that you will have to type the right PostScript name of the font you want to use, otherwise Xcode will not recognize it and will show the default font. The iOS Fonts site is a reference to the correct font names.
Here we'll also set the title and message strings with an instance of NSMutableAttributedString.
Let's create four actions, including the default Cancel one:
let action1 = UIAlertAction(title: "Action 1", style: .default, handler: { (action) -> Void in
print("ACTION 1 selected!")
})
let action2 = UIAlertAction(title: "Action 2", style: .default, handler: { (action) -> Void in
print("ACTION 2 selected!")
})
let action3 = UIAlertAction(title: "Action 3", style: .default, handler: { (action) -> Void in
print("ACTION 3 selected!")
})
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
Before attaching these actions to our alert, let's style it a little bit.
// Restyle the view of the Alert
alert.view.tintColor = UIColor.brown // change text color of the buttons
alert.view.backgroundColor = UIColor.cyan // change background color
alert.view.layer.cornerRadius = 25 // change corner radius
Although the UIAlertController API is limited, so that developers can't completely change its default structure, we can edit its style as we've done with the code above.
Finally we can add all actions and present our alert:
// Add action buttons and present the Alert
alert.addAction(action1)
alert.addAction(action2)
alert.addAction(action3)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
Now, if you run your code, you'll get something like this:
Conclusion
In this tutorial, we've created a series of custom UIAlertViews with text fields and custom styling. I hope you're able to put this knowledge into use for your next iOS app.
In the meantime, check out some of our other tutorials on Swift and iOS app development.
iOS 10 has just been released, and with it, Swift 3. Swift is a new programming language from Apple, designed specifically for creating iOS, macOS, and...
If you want to discover how to add photo effects in iOS, you've come to the right place. In this tutorial you'll create a simple app that will apply some...
In this tutorial, you will learn how to use the new UserNotificationsUI framework in iOS 10 to create custom interfaces for your app's local and push...
CodeCanyon has hundreds of iOS app templates that you can use to jump-start your development. This video will show you how to install and customize a...
A UIAlertController is used to display an alert message in an app. For example, if an error occurs, the alert can show a description and buttons to take further action. You can use alerts to make users log in or sign up, show the results of an action they made, or offer a few more settings options—for example when you have no room for extra buttons on a screen but you need users to be able to perform some more actions on a specific object in the app.
Since iOS 9, Apple has replaced UIAlertView with UIAlertController. You no longer have to add the UIAlertViewDelegate into your class and are now able to style your alert as you wish. You can customize the title and message fonts, change the background color, and add text fields.For the sake of this tutorial we have created a demo app with three buttons, and each one will fire a different customized alert. You can download it from the tutorial source repo on GitHub. Now let's see how easy it is to build these custom alerts!
Alert With a Text Field
The first alert we're going to build has a TextField attached where you can input anything you want from the iOS keyboard. In order to initialize a UIAlertController, you have to start with these three lines:
In the first line, we set a simple string as a title of the alert. In the second line is the message string that will be displayed right below the title. In the third line, the alert's type is set to .alert. (Another option is .actionSheet, but you can't customize an action sheet like you can an alert.)
In an alert controller, buttons are defined as UIAlertAction elements. So we're going to create a UIAlertAction, which will be the first button on the bottom-left side of our alert.
// Submit button
let submitAction = UIAlertAction(title: "Submit", style: .default, handler: { (action) -> Void in
// Get 1st TextField's text
let textField = alert.textFields![0]
print(textField.text!)
})
We've called this action submitAction, set its title to "Submit", given it the default style, and for its handler, printed the content of a text field. Since text fields in the alert have an index, we've selected the first one at position 0. Later on we'll see how to add multiple text fields to an alert.
Once you've tapped the Submit button in your alert, the Xcode console will print the text you've entered and dismiss the alert.
Let's create a button to just hide our alert:
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
As you can see, this action has no handler. That's because we want to dismiss the alert and perform no other actions. This button will show a red Cancel title because we've set its style as .destructive, which the Apple API will understand.
Before adding these two actions to the Alert, we have to initialize our text field:
// Add 1 textField and customize it
alert.addTextField { (textField: UITextField) in
textField.keyboardAppearance = .dark
textField.keyboardType = .default
textField.autocorrectionType = .default
textField.placeholder = "Type something here"
textField.clearButtonMode = .whileEditing
}
If you're familiar with UITextFields, you'll recognize these as standard attributes which set properties such as the keyboard appearance and type, autocorrection type, placeholder message, and clear button. (We've set the clear button to show up when you start typing something.)
Now, let's finish off our alert.
// Add action buttons and present the Alert
alert.addAction(submitAction)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
The UIAlertController doesn't handle arrays of actions, so we must add them one by one. Lastly, we present the alert as we would any other controller—with the present() function.
In our demo app, we've embedded all the code above into a Button, so if you run the app and tap it, you should see something like this:
If you type something in the empty text field and hit Submit, your Xcode console will print it out.
Alert With Three Text Fields
Now let's create a new alert with multiple Text Fields to create a login prompt. We'll start again with the three lines that initialize our alert:
We still have two Buttons, one to perform a login action and the cancel button:
// Login button
let loginAction = UIAlertAction(title: "Login", style: .default, handler: { (action) -> Void in
// Get TextFields text
let usernameTxt = alert.textFields![0]
let passwordTxt = alert.textFields![1]
let phoneTxt = alert.textFields![2]
print("USERNAME: \(usernameTxt.text!)\nPASSWORD: \(passwordTxt.text!)\nPHONE NO.: \(phoneTxt.text!)")
})
As you can see, our alert has three text fields. These are indexed by their position. We'll treat the top one as the user name, the middle one as the password, and the last one as a phone number.
Now add a Cancel button:
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
Next we're going to create and customize the username Text Field:
Since passwords must usually be hidden, we've set the isSecureTextEntry attribute on our Text Field. This command will replace characters that you type with dots, as password fields do on a website. We've also set the text color to red.
And the third text element, for the phone number field:
The keyboardType attribute is set as .numberPad here, so the app will display the numeric keyboard only. You may also notice that we've changed the font of this text field to American Typewriter in the last line of code.
We're almost done—we just need to add our actions and present the AlertController again:
// Add action buttons and present the Alert
alert.addAction(loginAction)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
Now, if you run the app and fire this alert, you will see something like this:
If you try typing something in the text fields, you'll see the custom styling we applied.
Alert With Four Buttons
For a final example, I'll show you an alert with four actions and some different styling.
Since we'll customize the title and message attributes of this alert later, our initialization code will have empty strings for now:
let alert = UIAlertController(title: "",
message: "",
preferredStyle: .alert)
Here's how we'll set up the font and size of the title and message fields:
// Change font of the title and message
let titleFont:[String : AnyObject] = [ NSFontAttributeName : UIFont(name: "AmericanTypewriter", size: 18)! ]
let messageFont:[String : AnyObject] = [ NSFontAttributeName : UIFont(name: "HelveticaNeue-Thin", size: 14)! ]
let attributedTitle = NSMutableAttributedString(string: "Multiple buttons", attributes: titleFont)
let attributedMessage = NSMutableAttributedString(string: "Select an Action", attributes: messageFont)
alert.setValue(attributedTitle, forKey: "attributedTitle")
alert.setValue(attributedMessage, forKey: "attributedMessage")
In the first two lines we set the font name and size as a Dictionary of NSFontAttributeName. Please note that you will have to type the right PostScript name of the font you want to use, otherwise Xcode will not recognize it and will show the default font. The iOS Fonts site is a reference to the correct font names.
Here we'll also set the title and message strings with an instance of NSMutableAttributedString.
Let's create four actions, including the default Cancel one:
let action1 = UIAlertAction(title: "Action 1", style: .default, handler: { (action) -> Void in
print("ACTION 1 selected!")
})
let action2 = UIAlertAction(title: "Action 2", style: .default, handler: { (action) -> Void in
print("ACTION 2 selected!")
})
let action3 = UIAlertAction(title: "Action 3", style: .default, handler: { (action) -> Void in
print("ACTION 3 selected!")
})
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
Before attaching these actions to our alert, let's style it a little bit.
// Restyle the view of the Alert
alert.view.tintColor = UIColor.brown // change text color of the buttons
alert.view.backgroundColor = UIColor.cyan // change background color
alert.view.layer.cornerRadius = 25 // change corner radius
Although the UIAlertController API is limited, so that developers can't completely change its default structure, we can edit its style as we've done with the code above.
Finally we can add all actions and present our alert:
// Add action buttons and present the Alert
alert.addAction(action1)
alert.addAction(action2)
alert.addAction(action3)
alert.addAction(cancel)
present(alert, animated: true, completion: nil)
Now, if you run your code, you'll get something like this:
Conclusion
In this tutorial, we've created a series of custom UIAlertViews with text fields and custom styling. I hope you're able to put this knowledge into use for your next iOS app.
In the meantime, check out some of our other tutorials on Swift and iOS app development.
iOS 10 has just been released, and with it, Swift 3. Swift is a new programming language from Apple, designed specifically for creating iOS, macOS, and...
If you want to discover how to add photo effects in iOS, you've come to the right place. In this tutorial you'll create a simple app that will apply some...
In this tutorial, you will learn how to use the new UserNotificationsUI framework in iOS 10 to create custom interfaces for your app's local and push...
CodeCanyon has hundreds of iOS app templates that you can use to jump-start your development. This video will show you how to install and customize a...
Is it better to earn $5,000 by working ten hours a day, or to earn $3,000 by working just one? Time is money, and it's the most important asset that we have.
Using an app template has two advantages:
It saves you time.
You learn something new, quickly.
To build an app using a template, you enter your data, change the logo, customize fonts, colors... and that's it.
Suppose you want to create a guide to points of interest (churches, museums, monuments or even parking, shops, etc.) in your city. You could create your app from scratch, and spend a lot of time designing the interface, writing the code, and implementing frameworks. Or you could use a template and have everything ready in a few hours—sometimes minutes!
And perhaps even more important, you save time not only in the realization of the app itself, but also in learning new concepts: you get to see in practice how new things work, so you can learn and assimilate new ideas much more quickly.
But we wanted to make a guide to our city, right? Let's see how to do it in ten minutes with appyMap.
Overview
With appyMap you can create your own app to help users discover points of interest grouped by categories, such as a reference app for stores or restaurants, a city guide or any other use that requires localizing places on a map. You can find the appyMap iOS location-based app template for download on CodeCanyon.
The appyMap structure is very simple, and consists of four screens: Home, Section, Detail, and Directions (which are provided by Apple Maps).
The home screen shows our main sections, inside which there are the points of interest.
Selecting a point of interest opens the detail screen with photos, descriptions, and an extra field (which can be used for address, opening hours, etc.) and a button to get travel directions. If a phone number is present, you can also call the point of interest from within the app.
Now let's look at how to insert our data in the app.
Entering App Data
There are two ways to enter your data: through local Plist files or using CloudKit, Apple's cloud platform. Each one has its own pros and cons.
Option 1: Local Plist Files
Plist files are files that you include in your app. They're a structured data document—not unlike a spreadsheet file.
You can edit Plist files with Xcode. This is the easiest way and is useful when you just need to change or add small amounts of data. Another way to add data to a Plist file is by converting a spreadsheet and importing it to Xcode. This is really handy when you have to manage a large amount of data.
Using Plist files to ship your app's data gives you two advantages:
Your app will not need an Internet connection to function properly.
Less lag: your app's Plist data will be loaded instantly on boot, while data stored in the cloud will always have some lag.
The downside of using local data is that, if you want to add or edit points of interest, you will have to release a new version of the app.
Configuring the Main Menu
Inside the Xcode project that comes with appyMap, open the Main.plist file—this file defines the main menu. Inside this file we see a list of items, which define the categories ("sections") of places of interest. Each item has three fields:
id: the unique id of the section, used also for ordering items
name: the name of the section
isFree: If set to "yes" the section is free, otherwise it's locked and can be unlocked with in-app purchase.
Each section can have an icon, which should have the same filename as the name of the section (see the picture below).
You can add as many sections you want: the new sections will be added at the end of the list, and the main menu collection view will scroll if need be.
Points of Interest
Once you have configured the main sections, you can start adding points of interest. For each section, appyMap will look for a Plist file with the same filename as the name that you choose for the section. So for example if you have a section called "Houses", appyMap will look for a file called Houses.plist, and it will read the places of interest for the Houses section from that file.
These places of interest files have the following fields:
id
name
description
latitude
longitude
tel (optional)
time(optional)
For the place of interest thumbnail image, the app will look for a JPEG image with a filename consisting of the name of the section followed by the id of the place of interest. So if you have three places in the Museum section, you need three pictures named Museum1.jpg, Museum2.jpg, and Museum3.jpg.
Option 2: CloudKit
Instead of storing your app information in local Plist files, you can serve it from Apple's CloudKit.
If you decide to use CloudKit, your information will no longer be local, but will be read from the cloud. This allows you to modify the database of places of interest without having to release new versions of the app. However, the app will require an Internet connection in order to show points of interest.
Using CloudKit
Using your Apple developer account, you can use the CloudKit back end to manage your data. If you have an Apple Developer account, you can manage CloudKit with the CloudKit Dashboard.
In order to connect your App with CloudKit, you have to go to your Developer Page, and enable iCloud:
Then, go back to Xcode, select your target, and enable iCloud for your app:
Now you need to add two record types to hold the app data. Starting with the Main type, to hold the sections menu data: go to your CloudKit dashboard, select Record Types, click on the plus button and name the record "Main". Now we need to recreate essentially the same structure that we used in the Plist file. Click on Add Field... and create four fields:
name (type: String)
pic (type: Asset)
order (type: Int(64))
isFree (type: Int(64))
This is a bit different from the Plist format, because we have created an extra field called "pic", which will hold the icon for each section.
At the end you should have a table like this:
Next you have to create a record type for each section that your app will display. So for example, if you have two sections (let's say "Houses" and "Monuments") for your app, you would create two corresponding records, named “Houses" and “Monuments" (as in the screenshot above).
To create another record type, start by clicking on the + button. Give the record the name of your section (in this case “Houses"):
Now click on Add Field... and create fields as you did before. This time, the fields that you have to create are the following:
name (type: String)
description (type: String)
pic (type: Asset)
coordinates (type: Location)
tel (type: String)
time (type: String)
order (type: Int64)
Note that the tel (telephone) and time fields are optional. If they are present, they will show up in the detail screen, otherwise they are hidden.
Hint: A Quick Way to Get Map Coordinates
Entering locations for appyMap involves looking up a lot of latitudes and longitudes. To quickly find the latitude and longitude of a given location, just look it up in Google Maps, right click on the point of interest, and select What's here? This will return all the place data, along with its latitude and longitude. You can just copy and paste these values to the lat and lon fields in CloudKit, or to your Plist file.
Conclusion
In this tutorial, you learned how to get started with a new location-based app using the appyMap template from CodeCanyon. You learned how the template works, and how to add your own location data to the template.
If you download the template, you'll get lots more information about how to set up and customize your app. appyMap comes with a detailed instruction guide that will take you through all the steps of configuring and customizing the template properly.
But it's easy. To build an app using a template, just enter your data, customize the colour, fonts, and logo... and compile! Your app can be ready in just a few hours.
There are hundreds of other iOS app templates on CodeCanyon. Go check them out! You might just save yourself many hours of work.
Good luck on your next app! And in the meantime, check out some of our other iOS app tutorials here on Envato Tuts+.
Welcome. Today, I'll guide you through adding your app to the Amazon Appstore. When you add your app to the Amazon Appstore, it's visible to Android and Fire users in more than 200 countries, and developers can now list their PC, Mac and HTML5-based web apps as well as Android apps. By submitting your app, web app or game to the program, you can grow your business and revenue.
According to Statista, there are currently more than 600,000 apps in the Amazon Appstore.
In addition to today's tutorial, you can find a breadth of helpful information at Amazon's Developer portal.
Already on Google Play?
If your Android app is already in the Google Play store, it's even easier to join the Amazon Appstore. Amazon reports that over 85% of Android apps just work on Kindle Fire with no additional development necessary. Here's a short video guiding you through the process, Moving from Google Play to the Amazon Appstore (video):
If you haven't added an app to the Amazon Appstore before, this tutorial will guide you through every step.
Before I get started, I want to encourage you to reach out with any questions you may have about the tutorial. Post them in the comments below or to me @lookahead_io on Twitter.
Getting Started With the Amazon Appstore
If you've been reading my other series at Envato Tuts+, you know about Building Your Startup. I'm going to use Meeting Planner as an example Android application and HTML5 website to add to the Appstore.
Once you've submitted the title and other details, you'll land on the tab-driven settings page. There are tabs for a number of registration areas:
General Information
Availability & Pricing
Description
Images & Multimedia
Content Rating
Binary Files or URLs
I'm going to walk through all of these today.
At this time, if you're interested in asking Amazon to spread the word about your app, click Advertise Your App:
Availability & Pricing
On the Availability & Pricing tab, you'll be introduced to Amazon's time-driven app-payment system for app engagement, The Underground:
Amazon Underground includes a new monetization model where Amazon pays developers based on the amount of time your app is used. With Amazon Underground, you can turn 100% of your Android users into revenue-generating customers. You get paid starting from the very first minute your Amazon Underground app is used, and you will continue to be paid for every minute of use by every customer in exchange for you waiving your normal download or in-app fees. With Amazon Underground, you can focus less on monetizing and more on creating great user experiences.
You can learn more about it at the Amazon Underground Developer Portal. And, of course, it's optional. You can still give away your app for free or charge buyers for it.
For simplicity, let's walk through the standard app flow. Here's what the form asks when you use traditional pricing:
Next you get to select which countries your app will be available in (if you don't choose in all countries...):
Here you'll specify the title, descriptions, feature benefits and keywords for your apps.
You can also create multiple translations very easily for the different international stores. Amazon has compiled best practices for filling in these fields in Eight Tips for Marketing Your App.
I used Google Translate to quickly generate a Spanish version as shown below:
Once you've submitted more than one language, you'll see them listed at the top of the tab. This allows you to navigate to them and edit each language.
Images & Multimedia
The Amazon Appstore requires that you generate graphical icons and screenshots in specific sizes for your listing.
If you're app will be available for Fire TV, you will also be required to add additional images:
Here's what the Images & Multimedia form looks like with my logos and screenshots uploaded:
There's also a recommended promotional image, and you can even upload videos:
Content Rating
Next, it's time to help viewers filter content. Does your app have nudity or sex? Promote intolerance? (I'm not sure what happens if you say it does.) You can also indicate if your app is for educational purposes:
You'll also need to specify other unique aspects of your app. Does it require users to log in? Does it advertise to them? Does it target children under 13 or promote gambling (hopefully not both)? Does your app use geolocation and user-generated content?
Amazon will also ask you to provide a link to your privacy policy:
Binary File(s)
Next, if you're uploading an app, you'll need to provide your APK file. You can also upload localized binary packages separately and in sequence.
And that's basically it.
Now, let's look at uploading a mobile HTML5 web app.
Mobile HTML5 Web Apps
Amazon provides this helpful video for web app developers looking to submit to the Appstore.
I hope you've enjoyed our guide to submitting your app to the Amazon Appstore. Please let us know which areas you'd like to see covered in more detail. You can post them in the comments below or reach me on Twitter @lookahead_io.
Welcome. Today, I'll guide you through adding your app to the Amazon Appstore. When you add your app to the Amazon Appstore, it's visible to Android and Fire users in more than 200 countries, and developers can now list their PC, Mac and HTML5-based web apps as well as Android apps. By submitting your app, web app or game to the program, you can grow your business and revenue.
According to Statista, there are currently more than 600,000 apps in the Amazon Appstore.
In addition to today's tutorial, you can find a breadth of helpful information at Amazon's Developer portal.
Already on Google Play?
If your Android app is already in the Google Play store, it's even easier to join the Amazon Appstore. Amazon reports that over 85% of Android apps just work on Kindle Fire with no additional development necessary. Here's a short video guiding you through the process, Moving from Google Play to the Amazon Appstore (video):
If you haven't added an app to the Amazon Appstore before, this tutorial will guide you through every step.
Before I get started, I want to encourage you to reach out with any questions you may have about the tutorial. Post them in the comments below or to me @lookahead_io on Twitter.
Getting Started With the Amazon Appstore
If you've been reading my other series at Envato Tuts+, you know about Building Your Startup. I'm going to use Meeting Planner as an example Android application and HTML5 website to add to the Appstore.
Once you've submitted the title and other details, you'll land on the tab-driven settings page. There are tabs for a number of registration areas:
General Information
Availability & Pricing
Description
Images & Multimedia
Content Rating
Binary Files or URLs
I'm going to walk through all of these today.
At this time, if you're interested in asking Amazon to spread the word about your app, click Advertise Your App:
Availability & Pricing
On the Availability & Pricing tab, you'll be introduced to Amazon's time-driven app-payment system for app engagement, The Underground:
Amazon Underground includes a new monetization model where Amazon pays developers based on the amount of time your app is used. With Amazon Underground, you can turn 100% of your Android users into revenue-generating customers. You get paid starting from the very first minute your Amazon Underground app is used, and you will continue to be paid for every minute of use by every customer in exchange for you waiving your normal download or in-app fees. With Amazon Underground, you can focus less on monetizing and more on creating great user experiences.
You can learn more about it at the Amazon Underground Developer Portal. And, of course, it's optional. You can still give away your app for free or charge buyers for it.
For simplicity, let's walk through the standard app flow. Here's what the form asks when you use traditional pricing:
Next you get to select which countries your app will be available in (if you don't choose in all countries...):
Here you'll specify the title, descriptions, feature benefits and keywords for your apps.
You can also create multiple translations very easily for the different international stores. Amazon has compiled best practices for filling in these fields in Eight Tips for Marketing Your App.
I used Google Translate to quickly generate a Spanish version as shown below:
Once you've submitted more than one language, you'll see them listed at the top of the tab. This allows you to navigate to them and edit each language.
Images & Multimedia
The Amazon Appstore requires that you generate graphical icons and screenshots in specific sizes for your listing.
If you're app will be available for Fire TV, you will also be required to add additional images:
Here's what the Images & Multimedia form looks like with my logos and screenshots uploaded:
There's also a recommended promotional image, and you can even upload videos:
Content Rating
Next, it's time to help viewers filter content. Does your app have nudity or sex? Promote intolerance? (I'm not sure what happens if you say it does.) You can also indicate if your app is for educational purposes:
You'll also need to specify other unique aspects of your app. Does it require users to log in? Does it advertise to them? Does it target children under 13 or promote gambling (hopefully not both)? Does your app use geolocation and user-generated content?
Amazon will also ask you to provide a link to your privacy policy:
Binary File(s)
Next, if you're uploading an app, you'll need to provide your APK file. You can also upload localized binary packages separately and in sequence.
And that's basically it.
Now, let's look at uploading a mobile HTML5 web app.
Mobile HTML5 Web Apps
Amazon provides this helpful video for web app developers looking to submit to the Appstore.
I hope you've enjoyed our guide to submitting your app to the Amazon Appstore. Please let us know which areas you'd like to see covered in more detail. You can post them in the comments below or reach me on Twitter @lookahead_io.
In-app purchase is a great feature for all those developers who want to get more revenue and offer extra content and features through their applications. For example, for games you can buy gems or coins, and for photography apps you may unlock new effects or tools. And you can do all this using a credit card or other payment method, without exiting the app.
In this tutorial I'll cover all the necessary steps to create a Consumable and Non-Consumable IAP product on iTunes Connect, and I'll show you the code you'll need to purchase both items. I've made a sample Xcode project with a label and two buttons, so download it and follow along with this tutorial to understand how it works.
Create a Sandbox Tester in iTunes Connect
I assume you've already created an iOS app in the My Apps section on iTunes Connect. The first thing you should do is create a Sandbox Tester to test IAP on your real device (no Simulator—it doesn't support In-App Purchases).
Enter Users and Roles, go to the Sandbox Tester tab, and click the (+) sign next to Tester.
Fill out the form to add a new sandbox tester. Once you've saved your info, go back to the My App section and click on the icon of your app to enter its details and create IAP products.
Create IAP Products in iTunes Connect
Consumable Products
Click the Features tab and then the (+) sign next to In-App Purchases. You can create one product at a time, so let's start with a Consumable one.
A Consumable IAP, as its name suggests, is a product that you can buy multiple times. We'll use it to collect additional "coins" in our demo app.
Click Create to initialize your IAP item. On the next screen, you can set up all the info about your product:
Reference Name: this name will be used on iTunes Connect and in Sales and Trends reports. It won't be displayed on the App Store and you can type any name you want, but it can't be longer than 64 characters.
Product ID: A unique alphanumeric identifier that will be fetched by the app in order to recognize your product. Usually developers use a web-reverse syntax for product ids. In this example we chose com.iaptutorial.coins. Later on we'll paste this ID as a string into our code.
Price: Choose a price tier from the dropdown menu. Remember that in order to sell your in-app purchase product on the App Store, you must have applied for a Paid Application Agreement in the Agreements, Tax & Banking section.
Localizations: For the sake of this tutorial we've chosen only English, but you can add more languages by clicking on the (+) button. Then type a Display Name and a Description. Both of them will be visible on the App Store.
Screenshot: Upload a screenshot for review. It will not be displayed in the App Store and it must have a valid size for your app platform, so if your app is Universal, you may upload an iPad screenshot.
Review Notes: Any additional information about your IAP which may be helpful for the reviewer.
Once you're done, click Save and you'll get this alert:
Your first In-App Purchase must be submitted with a new app version. Select it from the app’s In-App Purchases section and click Submit.
Non-Consumable Products
Now click the In-App Purchases button on the list on the left, right above the Game Center button, and add a new IAP product. This time, select the Non-Consumable option:
Click Create and repeat the steps we mentioned above. Since this will be a Non-Consumable product, users will be able to purchase it only once, and Apple requires the ability to restore such purchases. That happens in case you uninstall the app and reinstall it again, or download it from another device with your same Apple ID and need to get your purchases back without paying for them twice. So later we'll add a Restore Purchase function in our code.
The Product ID we created now is com.iaptutorial.premium, with a price tier of USD $2.99. We've called it Unlock Premium Version.
Once you're done filling all the fields, save your product and go back to the In-App Purchases page. Now you should have a list of your two products, with their Name, Type, ID and Status set as Ready to Submit.
Go back to your app's page by clicking on the App Store and Prepare for Submission buttons. Scroll down to the In-App Purchases section, right below General App Information, and click to the (+) button to add your IAP products.
Select all of them and click Done.
Finally, click Save in the top-right corner of the screen and you'll be done with configuring In-App Purchase products on iTunes Connect.
Log in to Sandbox Tester on an iOS device
Before getting to the code, there's one more thing left to do. Go to Settings > iTunes & App Store on your iOS device. If you're already logged in with your original Apple ID, tap on it and choose Sign Out. Then simply sign in with the credentials for the sandbox tester you created. After signing in, you may get an alert like this:
Just ignore its message and tap Cancel. Your device will ask you your sandbox login credentials again while trying to make a purchase and will recognize your test account so you won't be charged a penny on your credit card for any purchase you make.
Exit Settings, plug your device into your Mac via the USB cable, and let's finally start coding!
The Code
If you've downloaded our demo project, you'll see that all the necessary code for In-App Purchase has been written, so if you run it you'll get something like this:
If you want to test the app, you should change the Bundle Identifier to your own id. Otherwise, Xcode will not allow you to run the app on a real device and the app will not recognize the two IAP products you've created.
Enter ViewController.swift and check the code. First of all we've added an import statement for StoreKit and the delegates we need in order to track payment transactions and product requests.
import StoreKit
class ViewController: UIViewController,
SKProductsRequestDelegate,
SKPaymentTransactionObserver
{
Then we've declared a few views which will be useful.
/* Views */
@IBOutlet weak var coinsLabel: UILabel!
@IBOutlet weak var premiumLabel: UILabel!
@IBOutlet weak var consumableLabel: UILabel!
@IBOutlet weak var nonConsumableLabel: UILabel!
coinsLabel and premiumLabel will be used to show the results of purchases for both products. consumableLabel and nonConsumableLabel will show the description and price of each IAP product, the ones we've previously created in iTunes Connect.
Now it's time to add some variables:
/* Variables */
let COINS_PRODUCT_ID = "com.iaptutorial.coins"
let PREMIUM_PRODUCT_ID = "com.iaptutorial.premium"
var productID = ""
var productsRequest = SKProductsRequest()
var iapProducts = [SKProduct]()
var nonConsumablePurchaseMade = UserDefaults.standard.bool(forKey: "nonConsumablePurchaseMade")
var coins = UserDefaults.standard.integer(forKey: "coins")
The first two lines are to recall our product IDs. It's important that those strings exactly match the ones registered in iTunes Connect's In-App Purchase section.
productID is a string we'll be using later to detect what product we will choose to buy.
productsRequest is an instance of SKProductsRequest, needed to search for IAP products from your app on iTC.
iapProducts is a simple array of SKProducts. Please note that SK prefix means StoreKit, the iOS framework we'll be using to handle purchases.
The last two lines load two variables of type Boolean and Integer needed to track purchases of coins and the premium version, respectively consumable and non-consumable products.
The following code in viewDidLoad() performs a few things as soon as the app starts:
// Check your In-App Purchases
print("NON CONSUMABLE PURCHASE MADE: \(nonConsumablePurchaseMade)")
print("COINS: \(coins)")
// Set text
coinsLabel.text = "COINS: \(coins)"
if nonConsumablePurchaseMade { premiumLabel.text = "Premium version PURCHASED!"
} else { premiumLabel.text = "Premium version LOCKED!"}
// Fetch IAP Products available
fetchAvailableProducts()
First we just log each purchase to the Xcode console. Then we display the total amount of coins that we bought with the coinsLabel. Since we're running the demo app for the first time, it will show COINS: 0.
The if statement sets the premiumLabel's text according to whether the non-consumable product was purchased. To start off, it will show Premium version LOCKED! since we haven't made the premium purchase yet.
The last line of code calls a method we'll see later, which simply fetches the products we've previously stored in iTC.
Now let's see what the two purchase buttons we've set in our demo app do:
Both methods will call a function that will check if the device can make purchases, and if it can, the app will call the StoreKit delegate methods to process the purchase.
As mentioned before, we need a third button to restore our non-consumable purchase. Here is its code:
The IBAction function is attached to the Restore Purchase button in the Storyboard and starts connecting to Apple's In-App Purchase system to restore the purchase if that has been already made.
paymentQueueRestoreCompletedTransactionsFinished() is the delegate method from StoreKit framework that will save our nonConsumablePurchaseMade variable to true after the purchase has been successfully restored.
We're done with buttons, so let's see what the fetchAvailableProducts() function does:
// MARK: - FETCH AVAILABLE IAP PRODUCTS
func fetchAvailableProducts() {
// Put here your IAP Products ID's
let productIdentifiers = NSSet(objects:
COINS_PRODUCT_ID,
PREMIUM_PRODUCT_ID
)
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
We first create an instance of NSSet, which is basically an array of strings. We'll store the two product IDs we've previously declared there.
Then we start an SKProductsRequest based on those identifiers, in order for the app to display the info about the IAP products (description and price), which will be processed by this delegate method:
// MARK: - REQUEST IAP PRODUCTS
func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
if (response.products.count > 0) {
iapProducts = response.products
// 1st IAP Product (Consumable) ------------------------------------
let firstProduct = response.products[0] as SKProduct
// Get its price from iTunes Connect
let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.numberStyle = .currency
numberFormatter.locale = firstProduct.priceLocale
let price1Str = numberFormatter.string(from: firstProduct.price)
// Show its description
consumableLabel.text = firstProduct.localizedDescription + "\nfor just \(price1Str!)"
// ------------------------------------------------
// 2nd IAP Product (Non-Consumable) ------------------------------
let secondProd = response.products[1] as SKProduct
// Get its price from iTunes Connect
numberFormatter.locale = secondProd.priceLocale
let price2Str = numberFormatter.string(from: secondProd.price)
// Show its description
nonConsumableLabel.text = secondProd.localizedDescription + "\nfor just \(price2Str!)"
// ------------------------------------
}
}
In the function above we first have to check if there are any products registered in iTunes Connect and set our iapProducts array accordingly. Then we can initialize the two SKProducts and print their description and price on the labels.
Before getting to the core of the In-App Purchase code, we need a couple more functions:
// MARK: - MAKE PURCHASE OF A PRODUCT
func canMakePurchases() -> Bool { return SKPaymentQueue.canMakePayments() }
func purchaseMyProduct(product: SKProduct) {
if self.canMakePurchases() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
print("PRODUCT TO PURCHASE: \(product.productIdentifier)")
productID = product.productIdentifier
// IAP Purchases dsabled on the Device
} else {
UIAlertView(title: "IAP Tutorial",
message: "Purchases are disabled in your device!",
delegate: nil, cancelButtonTitle: "OK").show()
}
}
The first one checks if our device is able to make purchases. The second function is the one that we call from the two buttons. It starts the payment queue and changes our productID variable into the selected productIdentifier.
Now we've finally arrived at the last delegate method, the one that handles payment results:
// MARK:- IAP PAYMENT QUEUE
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
if let trans = transaction as? SKPaymentTransaction {
switch trans.transactionState {
case .purchased:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
// The Consumable product (10 coins) has been purchased -> gain 10 extra coins!
if productID == COINS_PRODUCT_ID {
// Add 10 coins and save their total amount
coins += 10
UserDefaults.standard.set(coins, forKey: "coins")
coinsLabel.text = "COINS: \(coins)"
UIAlertView(title: "IAP Tutorial",
message: "You've successfully bought 10 extra coins!",
delegate: nil,
cancelButtonTitle: "OK").show()
// The Non-Consumable product (Premium) has been purchased!
} else if productID == PREMIUM_PRODUCT_ID {
// Save your purchase locally (needed only for Non-Consumable IAP)
nonConsumablePurchaseMade = true
UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")
premiumLabel.text = "Premium version PURCHASED!"
UIAlertView(title: "IAP Tutorial",
message: "You've successfully unlocked the Premium version!",
delegate: nil,
cancelButtonTitle: "OK").show()
}
break
case .failed:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
case .restored:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
default: break
}}}
}
This function has a switch statement that checks every state of the payment. The first case gets called if the purchase has been successfully made and completes its transaction.
Inside this block we have to check what product ID we've selected and perform the necessary actions to update our app—so if we the user bought 10 extra coins, we'll add 10 to our coins variable, save its value with UserDefaults, display the new amount of coins we gained, and fire an alert about it.
Please note that you can make this purchase multiple times with no limits since it's a consumable IAP, and there's no need for a restore purchase function.
Similarly, if we bought the non-consumable premium product, the app sets our nonConsumablePurchaseMade variable to true, saves it, changes the text of the premiumLabel, and fires an alert to notify you that the purchase has been successful.
The other two cases handle the payment results for failure and restoring. The app will fire custom alerts on its own if your transaction fails for some reason or if you've restored a non-consumable purchase.
That's it! Now just make sure you're logged in with your Sandbox Tester credentials and run the app to test it. The first time, you'll get an alert like this:
Choose Use Existing Apple ID and enter your Sandbox Tester's username and password again to sign in. This happens because the app can recognize only a real user from the iTunes & App Store settings, not a Sandbox one.
Once you've logged in, you'll be able to perform purchases of both products.
There are hundreds of other iOS app templates on the Envato Market as well, ready to be reskinned and sure to speed up your workflow. Go check them out! You might just save hours of work on your next app.
Conclusion
In this tutorial, we've covered all the steps needed to create In-App Purchase products on iTunes Connect and how to write the code to enable them in your app. I hope you're able to put this knowledge to use in your next iOS app!
Thanks for reading, and I'll see you next time! Please check out our other courses and tutorials about iOS app development with Swift.
In-app purchase is a great feature for all those developers who want to get more revenue and offer extra content and features through their applications. For example, for games you can buy gems or coins, and for photography apps you may unlock new effects or tools. And you can do all this using a credit card or other payment method, without exiting the app.
In this tutorial I'll cover all the necessary steps to create a Consumable and Non-Consumable IAP product on iTunes Connect, and I'll show you the code you'll need to purchase both items. I've made a sample Xcode project with a label and two buttons, so download it and follow along with this tutorial to understand how it works.
Create a Sandbox Tester in iTunes Connect
I assume you've already created an iOS app in the My Apps section on iTunes Connect. The first thing you should do is create a Sandbox Tester to test IAP on your real device (no Simulator—it doesn't support In-App Purchases).
Enter Users and Roles, go to the Sandbox Tester tab, and click the (+) sign next to Tester.
Fill out the form to add a new sandbox tester. Once you've saved your info, go back to the My App section and click on the icon of your app to enter its details and create IAP products.
Create IAP Products in iTunes Connect
Consumable Products
Click the Features tab and then the (+) sign next to In-App Purchases. You can create one product at a time, so let's start with a Consumable one.
A Consumable IAP, as its name suggests, is a product that you can buy multiple times. We'll use it to collect additional "coins" in our demo app.
Click Create to initialize your IAP item. On the next screen, you can set up all the info about your product:
Reference Name: this name will be used on iTunes Connect and in Sales and Trends reports. It won't be displayed on the App Store and you can type any name you want, but it can't be longer than 64 characters.
Product ID: A unique alphanumeric identifier that will be fetched by the app in order to recognize your product. Usually developers use a web-reverse syntax for product ids. In this example we chose com.iaptutorial.coins. Later on we'll paste this ID as a string into our code.
Price: Choose a price tier from the dropdown menu. Remember that in order to sell your in-app purchase product on the App Store, you must have applied for a Paid Application Agreement in the Agreements, Tax & Banking section.
Localizations: For the sake of this tutorial we've chosen only English, but you can add more languages by clicking on the (+) button. Then type a Display Name and a Description. Both of them will be visible on the App Store.
Screenshot: Upload a screenshot for review. It will not be displayed in the App Store and it must have a valid size for your app platform, so if your app is Universal, you may upload an iPad screenshot.
Review Notes: Any additional information about your IAP which may be helpful for the reviewer.
Once you're done, click Save and you'll get this alert:
Your first In-App Purchase must be submitted with a new app version. Select it from the app’s In-App Purchases section and click Submit.
Non-Consumable Products
Now click the In-App Purchases button on the list on the left, right above the Game Center button, and add a new IAP product. This time, select the Non-Consumable option:
Click Create and repeat the steps we mentioned above. Since this will be a Non-Consumable product, users will be able to purchase it only once, and Apple requires the ability to restore such purchases. That happens in case you uninstall the app and reinstall it again, or download it from another device with your same Apple ID and need to get your purchases back without paying for them twice. So later we'll add a Restore Purchase function in our code.
The Product ID we created now is com.iaptutorial.premium, with a price tier of USD $2.99. We've called it Unlock Premium Version.
Once you're done filling all the fields, save your product and go back to the In-App Purchases page. Now you should have a list of your two products, with their Name, Type, ID and Status set as Ready to Submit.
Go back to your app's page by clicking on the App Store and Prepare for Submission buttons. Scroll down to the In-App Purchases section, right below General App Information, and click to the (+) button to add your IAP products.
Select all of them and click Done.
Finally, click Save in the top-right corner of the screen and you'll be done with configuring In-App Purchase products on iTunes Connect.
Log in to Sandbox Tester on an iOS device
Before getting to the code, there's one more thing left to do. Go to Settings > iTunes & App Store on your iOS device. If you're already logged in with your original Apple ID, tap on it and choose Sign Out. Then simply sign in with the credentials for the sandbox tester you created. After signing in, you may get an alert like this:
Just ignore its message and tap Cancel. Your device will ask you your sandbox login credentials again while trying to make a purchase and will recognize your test account so you won't be charged a penny on your credit card for any purchase you make.
Exit Settings, plug your device into your Mac via the USB cable, and let's finally start coding!
The Code
If you've downloaded our demo project, you'll see that all the necessary code for In-App Purchase has been written, so if you run it you'll get something like this:
If you want to test the app, you should change the Bundle Identifier to your own id. Otherwise, Xcode will not allow you to run the app on a real device and the app will not recognize the two IAP products you've created.
Enter ViewController.swift and check the code. First of all we've added an import statement for StoreKit and the delegates we need in order to track payment transactions and product requests.
import StoreKit
class ViewController: UIViewController,
SKProductsRequestDelegate,
SKPaymentTransactionObserver
{
Then we've declared a few views which will be useful.
/* Views */
@IBOutlet weak var coinsLabel: UILabel!
@IBOutlet weak var premiumLabel: UILabel!
@IBOutlet weak var consumableLabel: UILabel!
@IBOutlet weak var nonConsumableLabel: UILabel!
coinsLabel and premiumLabel will be used to show the results of purchases for both products. consumableLabel and nonConsumableLabel will show the description and price of each IAP product, the ones we've previously created in iTunes Connect.
Now it's time to add some variables:
/* Variables */
let COINS_PRODUCT_ID = "com.iaptutorial.coins"
let PREMIUM_PRODUCT_ID = "com.iaptutorial.premium"
var productID = ""
var productsRequest = SKProductsRequest()
var iapProducts = [SKProduct]()
var nonConsumablePurchaseMade = UserDefaults.standard.bool(forKey: "nonConsumablePurchaseMade")
var coins = UserDefaults.standard.integer(forKey: "coins")
The first two lines are to recall our product IDs. It's important that those strings exactly match the ones registered in iTunes Connect's In-App Purchase section.
productID is a string we'll be using later to detect what product we will choose to buy.
productsRequest is an instance of SKProductsRequest, needed to search for IAP products from your app on iTC.
iapProducts is a simple array of SKProducts. Please note that SK prefix means StoreKit, the iOS framework we'll be using to handle purchases.
The last two lines load two variables of type Boolean and Integer needed to track purchases of coins and the premium version, respectively consumable and non-consumable products.
The following code in viewDidLoad() performs a few things as soon as the app starts:
// Check your In-App Purchases
print("NON CONSUMABLE PURCHASE MADE: \(nonConsumablePurchaseMade)")
print("COINS: \(coins)")
// Set text
coinsLabel.text = "COINS: \(coins)"
if nonConsumablePurchaseMade { premiumLabel.text = "Premium version PURCHASED!"
} else { premiumLabel.text = "Premium version LOCKED!"}
// Fetch IAP Products available
fetchAvailableProducts()
First we just log each purchase to the Xcode console. Then we display the total amount of coins that we bought with the coinsLabel. Since we're running the demo app for the first time, it will show COINS: 0.
The if statement sets the premiumLabel's text according to whether the non-consumable product was purchased. To start off, it will show Premium version LOCKED! since we haven't made the premium purchase yet.
The last line of code calls a method we'll see later, which simply fetches the products we've previously stored in iTC.
Now let's see what the two purchase buttons we've set in our demo app do:
Both methods will call a function that will check if the device can make purchases, and if it can, the app will call the StoreKit delegate methods to process the purchase.
As mentioned before, we need a third button to restore our non-consumable purchase. Here is its code:
The IBAction function is attached to the Restore Purchase button in the Storyboard and starts connecting to Apple's In-App Purchase system to restore the purchase if that has been already made.
paymentQueueRestoreCompletedTransactionsFinished() is the delegate method from StoreKit framework that will save our nonConsumablePurchaseMade variable to true after the purchase has been successfully restored.
We're done with buttons, so let's see what the fetchAvailableProducts() function does:
// MARK: - FETCH AVAILABLE IAP PRODUCTS
func fetchAvailableProducts() {
// Put here your IAP Products ID's
let productIdentifiers = NSSet(objects:
COINS_PRODUCT_ID,
PREMIUM_PRODUCT_ID
)
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
We first create an instance of NSSet, which is basically an array of strings. We'll store the two product IDs we've previously declared there.
Then we start an SKProductsRequest based on those identifiers, in order for the app to display the info about the IAP products (description and price), which will be processed by this delegate method:
// MARK: - REQUEST IAP PRODUCTS
func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
if (response.products.count > 0) {
iapProducts = response.products
// 1st IAP Product (Consumable) ------------------------------------
let firstProduct = response.products[0] as SKProduct
// Get its price from iTunes Connect
let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.numberStyle = .currency
numberFormatter.locale = firstProduct.priceLocale
let price1Str = numberFormatter.string(from: firstProduct.price)
// Show its description
consumableLabel.text = firstProduct.localizedDescription + "\nfor just \(price1Str!)"
// ------------------------------------------------
// 2nd IAP Product (Non-Consumable) ------------------------------
let secondProd = response.products[1] as SKProduct
// Get its price from iTunes Connect
numberFormatter.locale = secondProd.priceLocale
let price2Str = numberFormatter.string(from: secondProd.price)
// Show its description
nonConsumableLabel.text = secondProd.localizedDescription + "\nfor just \(price2Str!)"
// ------------------------------------
}
}
In the function above we first have to check if there are any products registered in iTunes Connect and set our iapProducts array accordingly. Then we can initialize the two SKProducts and print their description and price on the labels.
Before getting to the core of the In-App Purchase code, we need a couple more functions:
// MARK: - MAKE PURCHASE OF A PRODUCT
func canMakePurchases() -> Bool { return SKPaymentQueue.canMakePayments() }
func purchaseMyProduct(product: SKProduct) {
if self.canMakePurchases() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
print("PRODUCT TO PURCHASE: \(product.productIdentifier)")
productID = product.productIdentifier
// IAP Purchases dsabled on the Device
} else {
UIAlertView(title: "IAP Tutorial",
message: "Purchases are disabled in your device!",
delegate: nil, cancelButtonTitle: "OK").show()
}
}
The first one checks if our device is able to make purchases. The second function is the one that we call from the two buttons. It starts the payment queue and changes our productID variable into the selected productIdentifier.
Now we've finally arrived at the last delegate method, the one that handles payment results:
// MARK:- IAP PAYMENT QUEUE
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
if let trans = transaction as? SKPaymentTransaction {
switch trans.transactionState {
case .purchased:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
// The Consumable product (10 coins) has been purchased -> gain 10 extra coins!
if productID == COINS_PRODUCT_ID {
// Add 10 coins and save their total amount
coins += 10
UserDefaults.standard.set(coins, forKey: "coins")
coinsLabel.text = "COINS: \(coins)"
UIAlertView(title: "IAP Tutorial",
message: "You've successfully bought 10 extra coins!",
delegate: nil,
cancelButtonTitle: "OK").show()
// The Non-Consumable product (Premium) has been purchased!
} else if productID == PREMIUM_PRODUCT_ID {
// Save your purchase locally (needed only for Non-Consumable IAP)
nonConsumablePurchaseMade = true
UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")
premiumLabel.text = "Premium version PURCHASED!"
UIAlertView(title: "IAP Tutorial",
message: "You've successfully unlocked the Premium version!",
delegate: nil,
cancelButtonTitle: "OK").show()
}
break
case .failed:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
case .restored:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
default: break
}}}
}
This function has a switch statement that checks every state of the payment. The first case gets called if the purchase has been successfully made and completes its transaction.
Inside this block we have to check what product ID we've selected and perform the necessary actions to update our app—so if we the user bought 10 extra coins, we'll add 10 to our coins variable, save its value with UserDefaults, display the new amount of coins we gained, and fire an alert about it.
Please note that you can make this purchase multiple times with no limits since it's a consumable IAP, and there's no need for a restore purchase function.
Similarly, if we bought the non-consumable premium product, the app sets our nonConsumablePurchaseMade variable to true, saves it, changes the text of the premiumLabel, and fires an alert to notify you that the purchase has been successful.
The other two cases handle the payment results for failure and restoring. The app will fire custom alerts on its own if your transaction fails for some reason or if you've restored a non-consumable purchase.
That's it! Now just make sure you're logged in with your Sandbox Tester credentials and run the app to test it. The first time, you'll get an alert like this:
Choose Use Existing Apple ID and enter your Sandbox Tester's username and password again to sign in. This happens because the app can recognize only a real user from the iTunes & App Store settings, not a Sandbox one.
Once you've logged in, you'll be able to perform purchases of both products.
There are hundreds of other iOS app templates on the Envato Market as well, ready to be reskinned and sure to speed up your workflow. Go check them out! You might just save hours of work on your next app.
Conclusion
In this tutorial, we've covered all the steps needed to create In-App Purchase products on iTunes Connect and how to write the code to enable them in your app. I hope you're able to put this knowledge to use in your next iOS app!
Thanks for reading, and I'll see you next time! Please check out our other courses and tutorials about iOS app development with Swift.
The BeoStore React Native template for e-commerce is a platform-independent e-commerce compatible store template that supports multiple languages and push notifications with Firebase.
Upon buying it on CodeCanyon, you will be able to download the zip file that contains the complete app template. After you unzip it, you'll need to change to the template folder in your shell and run npm install to fetch all dependencies.
You also need to give the gradlew script permission to execute with chmod +x. Then you can use the React Native command line tool to run the app.
All React Native code is in the app template. In the Constants.js file you can easily change debugging configuration or adapt the look and feel of your application like changing the toolbar colors.
I'm going to set them to green. You can reload an already running app by bringing up the developer menu with Cmd+M, or by using the shake gesture and selecting reload.
The BeoStore React Native template for e-commerce is a platform-independent e-commerce compatible store template that supports multiple languages and push notifications with Firebase.
Upon buying it on CodeCanyon, you will be able to download the zip file that contains the complete app template. After you unzip it, you'll need to change to the template folder in your shell and run npm install to fetch all dependencies.
You also need to give the gradlew script permission to execute with chmod +x. Then you can use the React Native command line tool to run the app.
All React Native code is in the app template. In the Constants.js file you can easily change debugging configuration or adapt the look and feel of your application like changing the toolbar colors.
I'm going to set them to green. You can reload an already running app by bringing up the developer menu with Cmd+M, or by using the shake gesture and selecting reload.
Android users today no longer have to open a browser and perform a search to learn about things they stumble upon while using an app. They can instead use an assistant. If you own a device that runs Android 6.0 or higher, you might already be familiar with its default assistant, which was initially called Google Now on Tap. Lately, its name has been changed to screen search.
Assistants, although context-sensitive, are usually not very accurate. To improve accuracy, app developers must use the Assist API. In this quick tip, I'll introduce the basics of the API, and I'll help you get started with creating your very own custom assistant.
1. Enabling the Default Assistant
If you've never used the assistant on your device or emulator, it's probably not enabled yet. To enable it, press and hold the home button. In the dialog that pops up, press the Yes, I'm in button.
You'll now be able to access the default assistant from any app by simply long-pressing the home button. It's worth noting that the default assistant is a part of the Google app, and works best only after you've signed in to your Google account.
2. Sending Information to the Assistant
The default assistant is very powerful. It can automatically provide context-sensitive information based on the current contents of the screen. It does so by analyzing the view hierarchy of the active activity.
To see it in action, create a new activity in your Android Studio project and add the following TextView widget, which has the name of a popular novel, to its layout:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Alice's Adventures in Wonderland"
android:id="@+id/my_text"
/>
If you run your app now and long-press the home button, the default assistant will display cards that are somewhat related to the contents of the TextView widget.
By sending additional information to the assistant, you can improve its accuracy. To do so, you must first override the onProvideAssistContent() method of your Activity class.
@Override
public void onProvideAssistContent(AssistContent outContent) {
super.onProvideAssistContent(outContent);
}
You can now use the AssistContent object to send information to the assistant. For example, if you want the assistant to display a card that lets the user read about the novel on Goodreads, you can use the setWebUri() method.
The Assist API also lets you pass structured data to the assistant using the setStructuredData() method, which expects a JSON-LD string. The easiest way to generate the JSON-LD string is to use the JSONObject class and its put() method.
The following sample code shows you how to generate and send structured data about the novel:
outContent.setStructuredData(
new JSONObject()
.put("@type", "Book")
.put("author", "Lewis Carroll")
.put("name", "Alice in Wonderland")
.put("description",
"This is an 1865 novel about a girl named Alice, " +
"who falls through a rabbit hole and " +
"enters a fantasy world."
).toString()
);
If you choose to hand-code your JSON-LD string, I suggest you make sure that it is valid using Google's Structured Data Testing Tool.
3. Creating a Custom Assistant
If you are not satisfied with the way the Google app's assistant handles your data, you should consider creating your own assistant. Doing so doesn't take much effort.
All custom assistants must have the following:
a VoiceInteractionService object
a VoiceInteractionSession object
a VoiceInteractionSessionService object
an XML meta-data file describing the custom assistant
First, create a new Java class called MyAssistantSession and make it a subclass of the VoiceInteractionSession class. At this point, Android Studio should automatically generate a constructor for it.
public class MyAssistantSession extends VoiceInteractionSession {
public MyAssistantSession(Context context) {
super(context);
}
}
By overriding the onHandleAssist() method of the class, you can define the behavior of your assistant. For now, let's just make it parse the JSON-LD string we generated in the previous step and display its contents as a Toast message. As you might have guessed, to retrieve the JSON-LD string, you must use the getStructuredData() method of the AssistContent object.
The following code shows you how to display the value of the JSON-LD string's description key as a Toast message.
A VoiceInteractionSession object must be instantiated inside a VoiceInteractionSessionService object. Therefore, create a new Java class called MyAssistantSessionService and make it a subclass of VoiceInteractionSessionService. Inside its onNewSession() method, call the constructor of MyAssistantSession.
public class MyAssistantSessionService
extends VoiceInteractionSessionService {
@Override
public VoiceInteractionSession onNewSession(Bundle bundle) {
return new MyAssistantSession(this);
}
}
Our assistant also needs a VoiceInteractionService object. Therefore, create one called MyAssistantService. You don't have to write any code inside it.
public class MyAssistantService extends VoiceInteractionService {
}
To specify the configuration details of the assistant, you must create an XML metadata file and place it in the res/xml folder of your project. The file's root element must be a <voice-interaction-service> tag specifying the fully qualified names of both the VoiceInteractionService and the VoiceInteractionSessionService subclasses.
To be able to use your custom assistant, you must set it as your Android device's default assistant. Therefore, open the Settings app and navigate to Apps > Default Apps > Assist & voice input. Next, click on the Assist app option to select your assistant.
At this point, if you run your app and long-press the home button, you should be able to see your custom assistant's Toast message.
Conclusion
In this quick tip, you learned how to use the Assist API to interact with assistants on the Android platform. You also learned how to create a rudimentary custom assistant. But a word of caution: because assistants can read almost all the text that is present on a user's screen, you must make sure that your custom assistant handles sensitive data in a secure manner.
To learn more about the Assist API, refer to its official documentation. And to learn more about cutting-edge coding and APIs for the Android platform, check out some of our other courses and tutorials here on Envato Tuts+!
Android users today no longer have to open a browser and perform a search to learn about things they stumble upon while using an app. They can instead use an assistant. If you own a device that runs Android 6.0 or higher, you might already be familiar with its default assistant, which was initially called Google Now on Tap. Lately, its name has been changed to screen search.
Assistants, although context-sensitive, are usually not very accurate. To improve accuracy, app developers must use the Assist API. In this quick tip, I'll introduce the basics of the API, and I'll help you get started with creating your very own custom assistant.
1. Enabling the Default Assistant
If you've never used the assistant on your device or emulator, it's probably not enabled yet. To enable it, press and hold the home button. In the dialog that pops up, press the Yes, I'm in button.
You'll now be able to access the default assistant from any app by simply long-pressing the home button. It's worth noting that the default assistant is a part of the Google app, and works best only after you've signed in to your Google account.
2. Sending Information to the Assistant
The default assistant is very powerful. It can automatically provide context-sensitive information based on the current contents of the screen. It does so by analyzing the view hierarchy of the active activity.
To see it in action, create a new activity in your Android Studio project and add the following TextView widget, which has the name of a popular novel, to its layout:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Alice's Adventures in Wonderland"
android:id="@+id/my_text"
/>
If you run your app now and long-press the home button, the default assistant will display cards that are somewhat related to the contents of the TextView widget.
By sending additional information to the assistant, you can improve its accuracy. To do so, you must first override the onProvideAssistContent() method of your Activity class.
@Override
public void onProvideAssistContent(AssistContent outContent) {
super.onProvideAssistContent(outContent);
}
You can now use the AssistContent object to send information to the assistant. For example, if you want the assistant to display a card that lets the user read about the novel on Goodreads, you can use the setWebUri() method.
The Assist API also lets you pass structured data to the assistant using the setStructuredData() method, which expects a JSON-LD string. The easiest way to generate the JSON-LD string is to use the JSONObject class and its put() method.
The following sample code shows you how to generate and send structured data about the novel:
outContent.setStructuredData(
new JSONObject()
.put("@type", "Book")
.put("author", "Lewis Carroll")
.put("name", "Alice in Wonderland")
.put("description",
"This is an 1865 novel about a girl named Alice, " +
"who falls through a rabbit hole and " +
"enters a fantasy world."
).toString()
);
If you choose to hand-code your JSON-LD string, I suggest you make sure that it is valid using Google's Structured Data Testing Tool.
3. Creating a Custom Assistant
If you are not satisfied with the way the Google app's assistant handles your data, you should consider creating your own assistant. Doing so doesn't take much effort.
All custom assistants must have the following:
a VoiceInteractionService object
a VoiceInteractionSession object
a VoiceInteractionSessionService object
an XML meta-data file describing the custom assistant
First, create a new Java class called MyAssistantSession and make it a subclass of the VoiceInteractionSession class. At this point, Android Studio should automatically generate a constructor for it.
public class MyAssistantSession extends VoiceInteractionSession {
public MyAssistantSession(Context context) {
super(context);
}
}
By overriding the onHandleAssist() method of the class, you can define the behavior of your assistant. For now, let's just make it parse the JSON-LD string we generated in the previous step and display its contents as a Toast message. As you might have guessed, to retrieve the JSON-LD string, you must use the getStructuredData() method of the AssistContent object.
The following code shows you how to display the value of the JSON-LD string's description key as a Toast message.
A VoiceInteractionSession object must be instantiated inside a VoiceInteractionSessionService object. Therefore, create a new Java class called MyAssistantSessionService and make it a subclass of VoiceInteractionSessionService. Inside its onNewSession() method, call the constructor of MyAssistantSession.
public class MyAssistantSessionService
extends VoiceInteractionSessionService {
@Override
public VoiceInteractionSession onNewSession(Bundle bundle) {
return new MyAssistantSession(this);
}
}
Our assistant also needs a VoiceInteractionService object. Therefore, create one called MyAssistantService. You don't have to write any code inside it.
public class MyAssistantService extends VoiceInteractionService {
}
To specify the configuration details of the assistant, you must create an XML metadata file and place it in the res/xml folder of your project. The file's root element must be a <voice-interaction-service> tag specifying the fully qualified names of both the VoiceInteractionService and the VoiceInteractionSessionService subclasses.
To be able to use your custom assistant, you must set it as your Android device's default assistant. Therefore, open the Settings app and navigate to Apps > Default Apps > Assist & voice input. Next, click on the Assist app option to select your assistant.
At this point, if you run your app and long-press the home button, you should be able to see your custom assistant's Toast message.
Conclusion
In this quick tip, you learned how to use the Assist API to interact with assistants on the Android platform. You also learned how to create a rudimentary custom assistant. But a word of caution: because assistants can read almost all the text that is present on a user's screen, you must make sure that your custom assistant handles sensitive data in a secure manner.
To learn more about the Assist API, refer to its official documentation. And to learn more about cutting-edge coding and APIs for the Android platform, check out some of our other courses and tutorials here on Envato Tuts+!