Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon

How-To Tutorials - Mobile

213 Articles
article-image-unit-testing-apps-android-studio
Troy Miles
15 Mar 2016
6 min read
Save for later

Unit Testing Apps with Android Studio

Troy Miles
15 Mar 2016
6 min read
We will need to create an Android app, get it all set up, then add a test project to it. Let's begin. 1. Start Android Studio and select new project. 2. Change the Application name to UTest. Click Next . 3. Click Next again. 4. Click Finish. Now that we have the project started, let’s set it up. Open the layout resource file:activity_main.xml. Add an ID to TextView. It should look as follows: <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.tekadept.utest.app.MainActivity" > <TextView android:id="@+id/greeting" android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> The random message Next we modify the MainActivity class. We are going to add some code that will display a random greeting message to the user. Modify MainActivity so that it looks like the following code: TextViewtxtGreeting; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtGreeting = (TextView)findViewById(R.id.greeting); Random rndGenerator = new Random(); int rnd = rndGenerator.nextInt(4); String greeting = getGreeting(rnd); txtGreeting.setText(greeting); } private String getGreeting(intmsgNumber) { String greeting; switch (msgNumber){ case 0: greeting = "Holamundo"; break ; case 1: greeting = "Bonjour tout le monde"; break ; case 2: greeting = "Ciao mondo"; break ; case 3: greeting = "Hallo Welt"; break ; default : greeting = "Hello world"; break ; } return greeting; } At this point, if you run the app, it should display one of four random greetings each time you run. We want to test the getGreeting method. We need to be sure that the string it returns matches the number we sent it. Currently, however, we have no way to know that. In order to add a test package, we need to hover over the package name. For my app, the package name is com.tekadept.utest.app . It is the line directly below the Java directory. The rest of the steps are as follows: Right click on the package name and choose New-> Package. Give your new package the name tests . Click OK. Right click on tests and choose New -> Java Class . Enter MainActivityTest as your name. Click OK from inside MainActivityTest. Currently, we are not extending from the proper base class. Let's fix that. Change the MainActivityTest class so it looks like the following code: package com.tekadept.utest.app.tests; import android.test.ActivityInstrumentationTestCase2; import com.tekadept.utest.app.MainActivity; public class MainActivityTestextends ActivityInstrumentationTestCase2<MainActivity>{ public MainActivityTest() { super (MainActivity.class); } } We've done two things. First, we changed the base class to ActivityInstrumentationTestCase2. Secondly, we added a constructor method. Before we can test the logic of the getGreeting method, we need to make it visible to outside classes by changing its modifier from private to public. Once we've done that, return to the MainActivityTest class and add a new method, testGetGreetings. This is shown in the following code: public void testGetGreeting() throws Exception { MainActivity activity = getActivity(); int count = 0; String result = activity.getGreeting(count); Assert.assertEquals("Holamundo", result); count = 1; result = activity.getGreeting(count); Assert.assertEquals("Bonjour tout le monde", result); count = 2; result = activity.getGreeting(count); Assert.assertEquals("Ciao mondo", result); count = 3; result = activity.getGreeting(count); Assert.assertEquals("Hallo Welt", result); } Time to test All we need to do now is create a configuration for our test package. Click Run -> Edit Configurations…. On the Run/Debug Configurations click the plus sign in the upper left hand corner. Click onAndroid Tests. For the name, enter test. Make sure the General tab is selected. For Module , choose app . For Test, choose All in Package . For Package , browse down to the test folder. The Android unit test must run on a device or emulator. I prefer having the choose dialog come up, so I've selected that option. You should select whichever option works best for you. Then click OK. At this point, you have a working app complete with a functioning unit test. To run the unit test, choose the test configuration from the drop-down menu to the left of the run button. Then click the run button. After building your app and running it on your selected device, Android Studio will show the test results. If you don't see the results, click the run button in the lower left hand corner of Android Studio. Green is good. Red means one or more tests have failed. Currently our one test should be passing, so everything should be green. In order to see a test fail, let's make a temporary change to the getGreeting method. Change the first greeting from "Holamundo" to "Adios mundo". Save your change and click the run button to run the tests again. This time the test should fail. You should see a message something like the following: The test runner shows the failure message and includes a stack trace of the failure. The first line of the stack trace shows that the test failed on line 17 of MainActivityTest . Don't forget to restore the MainActivity class' getGreeting method back to fix the failing unit test. Conclusion That is it for this post. You now know how to add a unit test package to Android Studio. If you had any trouble with this post, be sure to check out the complete source code to the UTest project on my GitHub repo at: https://github.com/Rockncoder/UTest. From 14th-20th March we're throwing the spotlight on iOS and Android, and asking you which one you think will win out in the future. Tell us - then save 50% on a selection of our very best Android and iOS titles! About the author Troy Miles, also known asthe Rockncoder, currently has fun writing full stack code with ASP.NET MVC or Node.js on the backend and web or mobile up front. He started coding over 30 years ago, cutting his teeth writing games for C64, Apple II, and IBM PCs. After burning out, he moved on to Windows system programming before catching Internet fever just before the dot net bubble burst. After realizing that mobile devices were the perfect window into backend data, he added mobile programming to his repertoire. He loves competing in hackathons and randomly posting interesting code nuggets on his blog: http://therockncoder.blogspot.com/.
Read more
  • 0
  • 0
  • 6013

article-image-how-to-build-an-android-todo-app-with-phonegap-html-and-jquery
Robi Sen
14 Mar 2016
12 min read
Save for later

How to Build an Android To-Do App with PhoneGap, HTML and jQuery

Robi Sen
14 Mar 2016
12 min read
In this post, we are going to create a simple HTML 5, JavaScript, and CSS application then use PhoneGap to build it and turn it into an Android application, which will be useful for game development. We will learn how to structure a PhoneGap project, leverage Eclipse ADT for development, and use Eclipse as our build tool. To follow along with this post, it is useful to have a decent working knowledge of JavaScript and HTML, otherwise you might find the examples challenging. Understanding the typical workflow Before we begin developing our application, let’s look quickly at a workflow for creating a PhoneGap application. Generally you want to design your web application UI, create your HTML, and then develop your JavaScript application code. Then you should test it on your web browser to make sure everything works the way you would like it to. Finally, you will want to build it with PhoneGap and try deploying it to an emulator or mobile phone to test. And, if you plan to sell your application on an app store, you of course need to deploy it to an app store. The To-Do app For the example in this post we are going to build a simple To-Do app. The code for the whole application can be found here, but for now we will be working with two main files: the index.html and the todo.js. Usually we would create a new application using the command line argument phonegap create myapp but for this post we will just reuse the application we already made in Post 1. So, open your Eclipse ADT bundle and navigate to your project, which is most likely called HelloWorld since that’s the default app name. Now expand the application in the left pane of Eclipse and expand the www folder. You should end up seeing something like this: When PhoneGap creates an Android project it automatically creates several directories. The www directory under the root directory is where you create all your HTML, CSS, JavaScript, and store assets to be used in your project. When you build your project, using Eclipse or the command line, PhoneGap will turn your web application into your Android application. So, now that we know where to build our web application, let’s get started. Our goal is to make something that looks like the application in the following figure, which is the HTML we want to use shown in the Chrome browser: First let’s open the existing index.html file in Eclipse. We are going to totally rewrite the file so you can just delete all the existing HTML. Now let’s add the following code as shown here: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="format-detection" content="telephone=no" /> <meta name="msapplication-tap-highlight" content="no" /> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" /> <title>PhoneGap ToDo</title> <link rel="stylesheet" type="text/css" href="css/jquery.mobile-1.4.3.min.css"> <link rel="stylesheet" type="text/css" href="css/index.css" /> <link rel="stylesheet" type="text/css" href="css/jquery.mobile-1.0.1.custom.css?" /> <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script> <script type="text/javascript"src="js/jquery.mobile-1.4.3.min.js"></script> </head> OK; there is a bunch of stuff going on in this code. If you are familiar with HTML, you can see this is where we are importing a majority of our style sheets and JavaScript. For this example we are going to make use of JQuery and JQuery Mobile. You can get JQuery from here http://jquery.com/download/ and JQuery mobile from here http://jquerymobile.com/download/, but it’s easier if you just download the files from GitHub here. Those files need to go under mytestapp/www/js. Next, download the style sheets from here on GitHub and put them in mytestapp/www/cs. You will also notice the use of the meta tag. PhoneGap uses the meta tag to help set preferences for your application such as window sizing of the application, scaling, and the like. For now this topic is too big for discussion, but we will address it in further posts. OK, with that being said, let’s work on the HTML for the GUI. Now add the code shown here: <body> <script type="text/javascript"src="js/todo.js"></script> <div id="index" data-url="index" data-role="page"> <div data-role="header"> <h1>PhoneGap ToDo</h1> </div> <div data-role="content"> <ul id="task_list" data-role="listview"> <li data-role="list-divider">Add a task</li> </ul> <form id="form_336" method="GET"> <div data-role="fieldcontain"> <label for="inp_337"></label> <input type="text" name="inp_337" id="inp_337" /> </div> <input id="add" type="button" data-icon="plus" value="Add"/> </form> </div></div> <div id="confirm" data-url="confirm" data-role="page"> <div data-role="header"> <h1>Finish Task</h1> </div> <div data-role="content"> Mark this task as<br> <a class="remove_task" href="#done" data-role="button" data-icon="delete" data-theme="f">Done</a> <a class="remove_task" href="#notdone" data-role="button" data-icon="check" data-theme="g">Not Done</a> <br><br> <a href="#index" data-role="button" data-icon="minus">Cancel</a> </div></div> <div id="done" data-url="done" data-role="page"> <div data-role="header"> <h1>Right On</h1> </div> <div data-role="content"> You did it<br><br> <a href="#index" data-role="button">Good Job</a> </div></div> <div id="notdone" data-url="notdone" data-role="page"> <div data-role="header"> <h1>Get to work!</h1> </div> <div data-role="content"> Keep at it<br><br> <a href="#index" data-role="button">Back</a> </div></div> </body> </html> This HTML should make the GUI you saw earlier in this post. Go ahead and save the HTML code. Now go to the js directory under www. Create a new file by right clicking and selecting create new file, text. Name the new file todo.js. Now open the file in Eclipse and add the following code: var todo = {}; /** Read the new task and add it to the list */ todo.add = function(event) { // Read the task from the input var task=$('input').val(); if (task) { // Add the task to array and refresh list todo.list[todo.list.length] = task; todo.refresh_list(); // Clear the input $('input').val(''); } event.prevetodoefault(); }; /** Remove the task which was marked as selected */ todo.remove = function() { // Remove from array and refresh list todo.list.splice(todo.selected,1); todo.refresh_list(); }; /** Recreate the entire list from the available list of tasks */ todo.refresh_list = function() { var $tasks = $('#task_list'), i; // Clear the existing task list $tasks.empty(); if (todo.list.length) { // Add the header $tasks.append('<li data-role="list-divider">To Do&#39;s</li>'); for (var i=0;i<todo.list.length;i++){ // Append each task var li = '<li><a data-rel="dialog" data-task="' + i + '" href="#confirm">' + todo.list[i] + '</a></li>' $tasks.append(li); } } // Add the header for addition of new tasks $tasks.append('<li data-role="list-divider">Add a task</li>'); // Use jQuery Mobile's listview method to refresh $tasks.listview('refresh'); // Store back the list localStorage.todo_list = JSON.stringify(todo.list || []); }; // Initialize the index page $(document).delegate('#index','pageinit', function() { // If no list is already present, initialize it if (!localStorage.todo_list) { localStorage.todo_list = "[]"; } // Load the list by parsing the JSON from localStorage todo.list = JSON.parse(localStorage.todo_list); $('#add').bind('vclick', todo.add); $('#task_list').on('vclick', 'li a', function() { todo.selected = $(this).data('task'); }); // Refresh the list everytime the page is reloaded $('#index').bind('pagebeforeshow', todo.refresh_list); }); // Bind the 'Done' and 'Not Done' buttons to task removal $(document).delegate('#confirm', 'pageinit', function(){ $('.remove_task').bind('vclick', todo.remove); }); // Make the transition in reverse for the buttons on the done and notdone pages $(document).delegate('#done, #notdone', 'pageinit', function(){ // We reverse transition for any button linking to index page $('[href="#index"]').attr('data-direction','reverse'); }) What todo.js does is store the task list as a JavaScript array. We then just create simple functions to add or remove from the array and then a function to update the list. To allow us to persist the task list we use HTML 5’s localStorage (for information on localStorage go here) to act like a simple data base and store simple name/value pairs directly in the browser. Because of this, we don’t need to use an actual database like SQLite or a custom file storage option. Now save the file and try out the application in your browser. Try playing with the application a bit to test out how it’s working. Once you can confirm that it’s working, build and deploy the application in the Android emulate via Eclipse. To do this create a custom “builder” in Eclipse to allow you to easily build or rebuild your PhoneGap applications each time you make want to make changes. Making Eclipse auto-build your PhoneGap apps One of the reasons we want to use the Eclipse ADT with PhoneGap is that we can simplify our workflow, assuming you’re doing most of your work targeting Android devices, by being able to do all of our web development, potentially native Android develop, testing, and building, all through Eclipse. Doing this, though, is not covered in the PhoneGap documentation and can cause a lot of confusion, since most people assume you have to use the PhoneGap CLI command line interface to do all the application building. To make your application auto-build, first right-click on the application and select Properties. Then select Builders. Now select New, which will pop up a configuration type screen. On this screen select Program. You should now see the Edit Configuration screen: Name the new builder “PhoneGap Builder” and for the location field select Browse File System and navigate to /android/cordova/build.bat under our mytestapp folder. Then, for a working directory, you will want to put in the path to your mytestapp root directory. Finally, you’ll want to use the argument - -local. Then select ok. What this will do is that every time you build the application in Eclipse it will run the build.bat file with the —local argument. This will build the .apk and update the project with your latest changes made in the application www directory. For this post that would be mytestappwww. Also, if you made any changes to the Android source code, which we will not in this post, those changes will be updated and applied to the APK build. Now that we have created a new builder, right-click on the project in the selected build. The application should now take a few seconds and then build. Once it has completed building, go ahead and select the project again and select Run As an Android application. Like what was shown in Post 1, expect this to take a few minutes as Eclipse starts the Android emulator and deploys the new Android app (you can find your Android app in mytestappplatformsandroidbin). You should now see something like the following: Go ahead and play around with the application. Summary In this post, you learned how to use PhoneGap and the Eclipse ADT to build your first real web application with HTML 5 and JQuery and then deploy it as a real Android application. You also used JQuery and HTML 5’s localStorage to simplify the creation of your GUI. Try playing around with your application and clean up the UI with CSS. In our next post we will dive deeper into working with PhoneGap to make our application more sophisticated and add additional capabilities using the phone’s camera and other sensors. About the author Robi Sen, CSO at Department 13, is an experienced inventor, serial entrepreneur, and futurist whose dynamic twenty-plus year career in technology, engineering, and research has led him to work on cutting edge projects for DARPA, TSWG, SOCOM, RRTO, NASA, DOE, and the DOD. Robi also has extensive experience in the commercial space, including the co-creation of several successful start-up companies. He has worked with companies such as UnderArmour, Sony, CISCO, IBM, and many others to help build out new products and services. Robi specializes in bringing his unique vision and thought process to difficult and complex problems allowing companies and organizations to find innovative solutions that they can rapidly operationalize or go to market with.
Read more
  • 0
  • 0
  • 10874

article-image-publication-apps
Packt
22 Feb 2016
10 min read
Save for later

Publication of Apps

Packt
22 Feb 2016
10 min read
Ever wondered if you could prepare and publish an app on Google Play and you needed a short article on how you could get this done quickly? Here it is! Go ahead, read this piece of article, and you'll be able to get your app running on Google Play. (For more resources related to this topic, see here.) Preparing to publish You probably don't want to upload any of the apps from this book, so the first step is to develop an app that you want to publish. Head over to https://play.google.com/apps/publish/ and follow the instructions to get a Google Play developer account. This was $25 at the time of writing and is a one-time charge with no limit on the number of apps you can publish. Creating an app icon Exactly how to design an icon is beyond the remit of this book. But, simply put, you need to create a nice image for each of the Android screen density categorizations. This is easier than it sounds. Design one nice app icon in your favorite drawing program and save it as a .png file. Then, visit http://romannurik.github.io/AndroidAssetStudio/icons-launcher.html. This will turn your single icon into a complete set of icons for every single screen density. Warning! The trade-off for using this service is that the website will collect your e-mail address for their own marketing purposes. There are many sites that offer a similar free service. Once you have downloaded your .zip file from the preceding site, you can simply copy the res folder from the download into the main folder within the project explorer. All icons at all densities have now been updated. Preparing the required resources When we log into Google Play to create a new listing in the store, there is nothing technical to handle, but we do need to prepare quite a few images that we will need to upload. Prepare upto 8 screenshots for each device type (a phone/tablet/TV/watch) that your app is compatible with. Don't crop or pad these images. Create a 512 x 512 pixel image that will be used to show off your app icon on the Google Play store. You can prepare your own icon, or the process of creating app icons that we just discussed will have already autogenerated icons for you. You also need to create three banner graphics, which are as follows: 1024 x 500 180 x 120 320 x 180 These can be screenshots, but it is usually worth taking a little time to create something a bit more special. If you are not artistically minded, you can place a screenshot inside some quite cool device art and then simply add a background image. You can generate some device art at https://developer.android.com/distribute/tools/promote/device-art.html. Then, just add the title or feature of your app to the background. The following banner was created with no skill at all, just with a pretty background purchased for $10 and the device art tool I just mentioned: Also, consider creating a video of your app. Recording video of your Android device is nearly impossible unless your device is rooted. I cannot recommend you to root your device; however, there is a tool called ARC (App Runtime for Chrome) that enables you to run APK files on your desktop. There is no debugging output, but it can run a demanding app a lot more smoothly than the emulator. It will then be quite simple to use a free, open source desktop capture program such as OBS (Open Broadcaster Software) to record your app running within ARC. You can learn more about ARC at https://developer.chrome.com/apps/getstarted_arc and about OBS at https://obsproject.com/. Building the publishable APK file What we are doing in this section is preparing the file that we will upload to Google Play. The format of the file we will create is .apk. This type of file is often referred to as an APK. The actual contents of this file are the compiled class files, all the resources that we've added, and the files and resources that Android Studio has autogenerated. We don't need to concern ourselves with the details, as we just need to follow these steps. The steps not only create the APK, but they also create a key and sign your app with the key. This process is required and it also protects the ownership of your app:   Note that this is not the same thing as copy protection/digital rights management. In Android Studio, open the project that you want to publish and navigate to Build | Generate Signed APK and a pop-up window will open, as shown: In the Generate Signed APK window, click on the Create new button. After this, you will see the New Key Store window, as shown in the following screenshot: In the Key store path field, browse to a location on your hard disk where you would like to keep your new key, and enter a name for your key store. If you don't have a preference, simply enter keys and click on OK. Add a password and then retype it to confirm it. Next, you need to choose an alias and type it into the Alias field. You can treat this like a name for your key. It can be any word that you like. Now, enter another password for the key itself and type it again to confirm. Leave Validity (years) at its default value of 25. Now, all you need to do is fill out your personal/business details. This doesn't need to be 100% complete as the only mandatory field is First and Last Name. Click on the OK button to continue. You will be taken back to the Generate Signed APK window with all the fields completed and ready to proceed, as shown in the following window: Now, click on Next to move to the next screen: Choose where you would like to export your new APK file and select release for the Build Type field. Click on Finish and Android Studio will build the shiny new APK into the location you've specified, ready to be uploaded to the App Store. Taking a backup of your key store in multiple safe places! The key store is extremely valuable. If you lose it, you will effectively lose control over your app. For example, if you try to update an app that you have on Google Play, it will need to be signed by the same key. Without it, you would not be able to update it. Think of the chaos if you had lots of users and your app needed a database update, but you had to issue a whole new app because of a lost key store. As we will need it quite soon, locate the file that has been built and ends in the .apk extension. Publishing the app Log in to your developer account at https://play.google.com/apps/publish/. From the left-hand side of your developer console, make sure that the All applications tab is selected, as shown: On the top right-hand side corner, click on the Add new application button, as shown in the next screenshot: Now, we have a bit of form filling to do, and you will need all the images from the Preparing to publish section that is near the start of the chapter. In the ADD NEW APPLICATION window shown next, choose a default language and type the title of your application: Now, click on the Upload APK button and then the Upload your first APK button and browse to the APK file that you built and signed in. Wait for the file to finish uploading: Now, from the inner left-hand side menu, click on Store Listing: We are faced with a fair bit of form filling here. If, however, you have all your images to hand, you can get through this in about 10 minutes. Almost all the fields are self-explanatory, and the ones that aren't have helpful tips next to the field entry box. Here are a few hints and tips to make the process smooth and produce a good end result: In the Full description and Short description fields, you enter the text that will be shown to potential users/buyers of your app. Be sure to make the description as enticing and exciting as you can. Mention all the best features in a clear list, but start the description with one sentence that sums up your app and what it does. Don't worry about the New content rating field as we will cover that in a minute. If you haven't built your app for tablet/phone devices, then don't add images in these tabs. If you have, however, make sure that you add a full range of images for each because these are the only images that the users of this type of device will see. When you have completed the form, click on the Save draft button at the top-right corner of the web page. Now, click on the Content rating tab and you can answer questions about your app to get a content rating that is valid (and sometimes varied) across multiple countries. The last tab you need to complete is the Pricing and Distribution tab. Click on this tab and choose the Paid or Free distribution button. Then, enter a price if you've chosen Paid. Note that if you choose Free, you can never change this. You can, however, unpublish it. If you chose Paid, you can click on Auto-convert prices now to set up equivalent pricing for all currencies around the world. In the DISTRIBUTE IN THESE COUNTRIES section, you can select countries individually or check the SELECT ALL COUNTRIES checkbox, as shown in the next screenshot:   The next six options under the Device categories and User programs sections in the context of what you have learned in this book should all be left unchecked. Do read the tips to find out more about Android Wear, Android TV, Android Auto, Designed for families, Google Play for work, and Google Play for education, however. Finally, you must check two boxes to agree with the Google consent guidelines and US export laws. Click on the Publish App button in the top-right corner of the web page and your app will soon be live on Google Play. Congratulations. Summary You can now start building Android apps. Don't run off and build the next Evernote, Runtatstic, or Angry Birds just yet. Head over to our book, Android Programming for Beginners: https://www.packtpub.com/application-development/android-programming-beginners. Here are a few more books that you can check out to learn more about Android: Android Studio Cookbook (https://www.packtpub.com/application-development/android-studio-cookbook) Learning Android Google Maps (https://www.packtpub.com/application-development/learning-android-google-maps) Android 6 Essentials (https://www.packtpub.com/application-development/android-6-essentials) Android Sensor Programming By Example (https://www.packtpub.com/application-development/android-sensor-programming-example) Resources for Article: Further resources on this subject: Saying Hello to Unity and Android[article] Android and iOS Apps Testing at a Glance[article] Testing with the Android SDK[article]
Read more
  • 0
  • 0
  • 2030
Banner background image

article-image-cross-platform-solution-xamarinforms-and-mvvm-architecture
Packt
22 Feb 2016
9 min read
Save for later

A cross-platform solution with Xamarin.Forms and MVVM architecture

Packt
22 Feb 2016
9 min read
In this article by George Taskos, the author of the book, Xamarin Cross Platform Development Cookbook, we will discuss a cross-platform solution with Xamarin.Forms and MVVM architecture. Creating a cross-platform solution correctly requires a lot of things to be taken under consideration. In this article, we will quickly provide you with a starter MVVM architecture showing data retrieved over the network in a ListView control. (For more resources related to this topic, see here.) How to do it... In Xamarin Studio, click on File | New | Xamarin.Forms App. Provide the name XamFormsMVVM. Add the NuGet dependencies by right-clicking on each project in the solution and choosing Add | Add NuGet Packages…. Search for the packages XLabs.Forms and modernhttpclient, and install them. Repeat step 2 for the XamFormsMVVM portable class library and add the packages Microsoft.Net.Http and Newtonsoft.Json. In the XamFormsMVVM portable class library, create the following folders: Models, ViewModels, and Views. To create a folder, right-click on the project and select Add | New Folder. Right-click on the Models folder and select Add | New File…, choose the General | Empty Interface template, name it IDataService, and click on New, and add the following code: public interface IDataService { Task<IEnumerable<OrderModel>> GetOrdersAsync (); } Right-click on the Models folder again and select Add | New File…, choose the General | Empty Class template, name it DataService, and click on New, and add the following code: [assembly: Xamarin.Forms.Dependency (typeof (DataService))] namespace XamFormsMVVM{ public class DataService : IDataService { protected const string BaseUrlAddress = @"https://api.parse.com/1/classes"; protected virtual HttpClient GetHttpClient() { HttpClient httpClient = new HttpClient(new NativeMessageHandler()); httpClient.BaseAddress = new Uri(BaseUrlAddress); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue ("application/json")); return httpClient; } public async Task<IEnumerable<OrderModel>> GetOrdersAsync () { using (HttpClient client = GetHttpClient ()) { HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, client.BaseAddress + "/Order"); requestMessage.Headers.Add("X-Parse- Application-Id", "fwpMhK1Ot1hM9ZA4iVRj49VFz DePwILBPjY7wVFy"); requestMessage.Headers.Add("X-Parse-REST- API-Key", "egeLQVTC7IsQJGd8GtRj3ttJV RECIZgFgR2uvmsr"); HttpResponseMessage response = await client.SendAsync(requestMessage); response.EnsureSuccessStatusCode (); string ordersJson = await response.Content.ReadAsStringAsync(); JObject jsonObj = JObject.Parse (ordersJson); JArray ordersResults = (JArray)jsonObj ["results"]; return JsonConvert.DeserializeObject <List<OrderModel>> (ordersResults.ToString ()); } } } } Right-click on the Models folder and select Add | New File…, choose the General | Empty Interface template, name it IDataRepository, and click on New, and add the following code: public interface IDataRepository { Task<IEnumerable<OrderViewModel>> GetOrdersAsync (); } Right-click on the Models folder and select Add | New File…, choose the General | Empty Class template, name it DataRepository, and click on New, and add the following code in that file: [assembly: Xamarin.Forms.Dependency (typeof (DataRepository))] namespace XamFormsMVVM { public class DataRepository : IDataRepository { private IDataService DataService { get; set; } public DataRepository () : this(DependencyService.Get<IDataService> ()) { } public DataRepository (IDataService dataService) { DataService = dataService; } public async Task<IEnumerable<OrderViewModel>> GetOrdersAsync () { IEnumerable<OrderModel> orders = await DataService.GetOrdersAsync ().ConfigureAwait (false); return orders.Select (o => new OrderViewModel (o)); } } } In the ViewModels folder, right-click on Add | New File… and name it OrderViewModel. Add the following code in that file: public class OrderViewModel : XLabs.Forms.Mvvm.ViewModel { string _orderNumber; public string OrderNumber { get { return _orderNumber; } set { SetProperty (ref _orderNumber, value); } } public OrderViewModel (OrderModel order) { OrderNumber = order.OrderNumber; } public override string ToString () { return string.Format ("[{0}]", OrderNumber); } } Repeat step 5 and create a class named OrderListViewModel.cs: public class OrderListViewModel : XLabs.Forms.Mvvm.ViewModel{ protected IDataRepository DataRepository { get; set; } ObservableCollection<OrderViewModel> _orders; public ObservableCollection<OrderViewModel> Orders { get { return _orders; } set { SetProperty (ref _orders, value); } } public OrderListViewModel () : this(DependencyService.Get<IDataRepository> ()) { } public OrderListViewModel (IDataRepository dataRepository) { DataRepository = dataRepository; DataRepository.GetOrdersAsync ().ContinueWith (antecedent => { if (antecedent.Status == TaskStatus.RanToCompletion) { Orders = new ObservableCollection<OrderViewModel> (antecedent.Result); } }, TaskScheduler. FromCurrentSynchronizationContext ()); } } Right-click on the Views folder and choose Add | New File…, select the Forms | Forms Content Page Xaml, name it OrderListView, and click on New: <?xml version="1.0" encoding="UTF-8"?> <ContentPage x_Class="XamFormsMVVM.OrderListView" Title="Orders"> <ContentPage.Content> <ListView ItemsSource="{Binding Orders}"/> </ContentPage.Content> </ContentPage> Go to XmaFormsMVVM.cs and replace the contents with the following code: public App() { if (!Resolver.IsSet) { SetIoc (); } RegisterViews(); MainPage = new NavigationPage((Page)ViewFactory. CreatePage<OrderListViewModel, OrderListView>()); } private void SetIoc() { var resolverContainer = new SimpleContainer(); Resolver.SetResolver (resolverContainer.GetResolver()); } private void RegisterViews() { ViewFactory.Register<OrderListView, OrderListViewModel>(); } Run the application, and you will get results like the following screenshots: For Android: For iOS: How it works… A cross-platform solution should share as much logic and common operations as possible, such as retrieving and/or updating data in a local database or over the network, having your logic centralized, and coordinating components. With Xamarin.Forms, you even have a cross-platform UI, but this shouldn't stop you from separating the concerns correctly; the more abstracted you are from the user interface and programming against interfaces, the easier it is to adapt to changes and remove or add components. Starting with models and creating a DataService implementation class with its equivalent interface, IDataService retrieves raw JSON data over the network from the Parse API and converts it to a list of OrderModel, which are POCO classes with just one property. Every time you invoke the GetOrdersAsync method, you get the same 100 orders from the server. Notice how we used the Dependency attribute declaration above the namespace to instruct DependencyService that we want to register this implementation class for the interface. We took a step to improve the performance of the REST client API; although we do use the HTTPClient package, we pass a delegate handler, NativeMessageHandler, when constructing in the GetClient() method. This handler is part of the modernhttpclient NuGet package and it manages undercover to use a native REST API for each platform: NSURLSession in iOS and OkHttp in Android. The IDataService interface is used by the DataRepository implementation, which acts as a simple intermediate repository layer converting the POCO OrderModel received from the server in OrderViewModel instances. Any model that is meant to be used on a view is a ViewModel, the view's model, and also, when retrieving and updating data, you don't carry business logic. Only data logic that is known should be included as data transfer objects. Dependencies, such as in our case, where we have a dependency of IDataService for the DataRepository to work, should be clear to classes that will use the component, which is why we create a default empty constructor required from the XLabs ViewFactory class, but in reality, we always invoke the constructor that accepts an IDataService instance; this way, when we unit test this unit, we can pass our mock IDataService class and test the functionality of the methods. We are using the DependencyService class to register the implementation to its equivalent IDataRepository interface here as well. OrderViewModel inherits XLabs.Forms.ViewModel; it is a simple ViewModel class with one property raising property change notifications and accepting an OrderModel instance as a dependency in the default constructor. We override the ToString() method too for a default string representation of the object, which simplifies the ListView control without requiring us, in our example, to use a custom cell with DataTemplate. The second ViewModel in our architecture is the OrderListViewModel, which inherits XLabs.Forms.ViewModel too and has a dependency of IDataRepository, following the same pattern with a default constructor and a constructor with the dependency argument. This ViewModel is responsible for retrieving a list of OrderViewModel and holding it to an ObservableCollection<OrderViewModel> instance that raises collection change notifications. In the constructor, we invoke the GetOrdersAsync() method and register an action delegate handler to be invoked on the main thread when the task has finished passing the orders received in a new ObservableCollection<OrderViewModel> instance set to the Orders property. The view of this recipe is super simple: in XAML, we set the title property which is used in the navigation bar for each platform and we leverage the built-in data-binding mechanism of Xamarin.Forms to bind the Orders property in the ListView ItemsSource property. This is how we abstract the ViewModel from the view. But we need to provide a BindingContext class to the view while still not coupling the ViewModel to the view, and Xamarin Forms Labs is a great framework for filling the gap. XLabs has a ViewFactory class; with this API, we can register the mapping between a view and a ViewModel, and the framework will take care of injecting our ViewModel into the BindingContext class of the view. When a page is required in our application, we use the ViewFactory.CreatePage class, which will construct and provide us with the desired instance. Xamarin Forms Labs uses a dependency resolver internally; this has to be set up early in the application startup entry point, so it is handled in the App.cs constructor. Run the iOS application in the simulator or device and in your preferred Android emulator or device; the result is the same with the equivalent native themes for each platform. Summary Xamarin.Forms is a great cross-platform UI framework that you can use to describe your user interface code declaratives in XAML, and it will be translated into the equivalent native views and pages with the ability of customizing each native application layer. Xamarin.Forms and MVVM are made for each other; the pattern fits naturally into the design of native cross-platform mobile applications and abstracts the view from the data easy using the built-in data-binding mechanism. Resources for Article: Further resources on this subject: Code Sharing Between iOS and Android [Article] Working with Xamarin.Android [Article] Sharing with MvvmCross [Article]
Read more
  • 0
  • 0
  • 5246

article-image-building-your-first-android-wear-application
Packt
18 Feb 2016
18 min read
Save for later

Building your first Android Wear Application

Packt
18 Feb 2016
18 min read
One of the most exciting new directions that Android has gone in recently, is the extension of the platform from phones and tablets to televisions, car dashboards and wearables such as watches. These new devices allow us to provide added functionality to our existing apps, as well as creating wholly original apps designed specifically for these new environments. This article is really concerned with explaining the idiosyncrasies of each platform and the guidelines Google is keen for us to follow. This is particularly vital when it comes to developing apps that people will use when driving, as safety has to be of prime importance. There are also certain technical issues that need to be addressed when developing wearable apps, such as the pairing of the device with a handset and the entirely different UI and methods of use. In this article, you will: Create wearable AVDs Connect a wearable emulator to a handset with adb commands Connect a wearable emulator to a handset emulator Create a project with both mobile and wearable modules Use the Wearable UI Library Create shape-aware layouts Create and customize cards for wearables Understand wearable design principles (For more resources related to this topic, see here.) Android Wear Creating or adapting apps for wearables is probably the most complicated factors and requires a little more setting up than the other projects. However, wearables often give us access to one of the more fun new sensors, the heart rate monitor. In seeing how this works, we also get to see, how to manage sensors in general. Do not worry if you do not have access to an Android wearable device, as we will be constructing AVDs. You will ideally have an actual Android 5 handset, if you wish to pair it with the AVD. If you do not, it is still possible to work with two emulators but it is a little more complex to set up. Bearing this in mind, we can now prepare our first wearable app. Constructing and connecting to a wearable AVD It is perfectly possible to develop and test wearable apps on the emulator alone, but if we want to test all wearable features, we will need to pair it with a phone or a tablet. The next exercise assumes that you have an actual device. If you do not, still complete tasks 1 through 4 and we will cover how the rest can be achieved with an emulator a little later on. Open Android Studio. You do not need to start a project at this point. Start the SDK Manager and ensure you have the relevant packages installed. Open the AVD Manager. Create two new Android Wear AVDs, one round and one square, like so: Ensure USB Debugging is selected on your handset. Install the Android Wear app from the Play Store at this URL: https://play.google.com/store/apps/details?id=com.google.android.wearable.app. Connect it to your computer and start one of the AVDs we just created. Locate and open the folder containing the adb.exe file. It will probably be something like userAppDataLocalAndroidsdkplatform-tools. Using Shift + right-click, select Open command window here. In the command window, issue the following command: adb -d forward tcp:5601 tcp:5601 Launch the companion app and follow the instructions to pair the two devices. Being able to connect a real-world device to an AVD is a great way to develop form factors without having to own the devices. The wearable companion app simplifies the process of connecting the two. If you have had the emulator running for any length of time, you will have noticed that many actions, such as notifications, are sent to the wearable automatically. This means that very often our apps will link seamlessly with a wearable device, without us having to include code to pre-empt this. The adb.exe (Android Debug Bridge) is a vital part of our development toolkit. Most of the time, the Android Studio manages it for us. However, it is useful to know that it is there and a little about how to interact with it. We used it here to manually open a port between our wearable AVD and our handset. There are many adb commands that can be issued from the command prompt and perhaps the most useful is adb devices, which lists all currently debuggable devices and emulators, and is very handy when things are not working, to see if an emulator needs restarting. Switching the ADB off and on can be achieved using adb kill-server and adb start-server respectively. Using adb help will list all available commands. The port forwarding command we used in Step 10, needs to be issued every time the phone is disconnected from the computer. Without writing any code as such, we have already seen some of the features that are built into an Android Wear device and the way that the Wear UI differs from most other Android devices. Even if you usually develop with the latest Android hardware, it is often still a good idea to use an emulator, especially for testing the latest SDK updates and pre-releases. If you do not have a real device, then the next, small section will show you how to connect your wearable AVD to a handset AVD. Connecting a wearable AVD with another emulator Pairing two emulators is very similar to pairing with a real device. The main difference is the way we install the companion app without access to the Play Store. Follow these steps to see how it is done: Start up, an AVD. This will need to be targeting Google APIs as seen here: Download the com.google.android.wearable.app-2.apk. There are many places online where it can be found with a simple search, I used www.file-upload.net/download. Place the file in your sdk/platform-tools directory. Shift + right-click in this folder and select Open command window here. Enter the following command: adb install com.google.android.wearable.app-2.apk. Start your wearable AVD. Enter adb devices into the command prompt, making sure that both emulators are visible with an output similar to this: List of devices attached emulator-5554 device emulator-5555 device Enter adb telnet localhost 5554 at the command prompt, where 5554 is the phone emulator. Next, enter adb redir add tcp:5601:5601. You can now use the Wear app on the handheld AVD to connect to the watch. As we've just seen, setting up a Wear project takes a little longer than some of the other exercises we have performed. Once set up though, the process is very similar to that of developing for other form factors, and something we can now get on with. Creating a wearable project All of the apps that we have developed so far, have required just a single module, and this makes sense as we have only been building for single devices. In this next step, we will be developing across two devices and so will need two modules. This is very simple to do, as you will see in these next steps. Start a new project in the Android Studio and call it something like Wearable App. On the Target Android Devices screen, select both Phone and Tablet and Wear, like so: You will be asked to add two Activities. Select Blank Activity for the Mobile Activity and Blank Wear Activity for Wear. Everything else can be left as it is. Run the app on both round and square virtual devices. The first thing you will have noticed is the two modules, mobile and wear. The first is the same as we have seen many times, but there are a few subtle differences with the wear module and it is worth taking a little look at. The most important difference is the WatchViewStub class. The way it is used can be seen in the activity_main.xml and MainActivity.java files of the wear module. This frame layout extension is designed specifically for wearables and detects the shape of the device, so that the appropriate layout is inflated. Utilizing the WatchViewStub is not quite as straightforward, as one might imagine, as the appropriate layout is only inflated after the WatchViewStub has done its thing. This means that, to access any views within the layout, we need to employ a special listener that is called once the layout has been inflated. How this OnLayoutInflatedListener() works can be seen by opening the MainActivity.java file in the wear module and examining the onCreate() method, which will look like this: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { mTextView = (TextView) stub.findViewById(R.id.text); } }); } Other than the way that wearable apps and devices are set up for developing, the other significant difference is the UI. The widgets and layouts that we use for phones and tablets are not suitable, in most cases, for the diminished size of a watch screen. Android provides a whole new set of UI components, that we can use and this is what we will look at next. Designing a UI for wearables As well as having to consider the small size of wearable when designing layouts, we also have the issue of shape. Designing for a round screen brings its own challenges, but fortunately the Wearable UI Library makes this very simple. As well as the WatchViewStub, that we encountered in the previous section that inflates the correct layout, there is also a way to design a single layout that inflates in such a way, that it is suitable for both square and round screens. Designing the layout The project setup wizard included this library for us automatically in the build.gradle (Module: wear) file as a dependency: compile 'com.google.android.support:wearable:1.1.0' The following steps demonstrate how to create a shape-aware layout with a BoxInsetLayout: Open the project we created in the last section. You will need three images that must be placed in the drawable folder of the wear module: one called background_image of around 320x320 px and two of around 50x50 px, called right_icon and left_icon. Open the activity_main.xml file in the wear module. Replace its content with the following code: <android.support.wearable.view.BoxInsetLayout android_background="@drawable/background_image" android_layout_height="match_parent" android_layout_width="match_parent" android_padding="15dp"> </android.support.wearable.view.BoxInsetLayout> Inside the BoxInsetLayout, add the following FrameLayout: <FrameLayout android_id="@+id/wearable_layout" android_layout_width="match_parent" android_layout_height="match_parent" android_padding="5dp" app_layout_box="all"> </FrameLayout> Inside this, add these three views: <TextView android_gravity="center" android_layout_height="wrap_content" android_layout_width="match_parent" android_text="Weather warning" android_textColor="@color/black" /> <ImageView android_layout_gravity="bottom|left" android_layout_height="60dp" android_layout_width="60dp" android_src="@drawable/left_icon" /> <ImageView android_layout_gravity="bottom|right" android_layout_height="60dp" android_layout_width="60dp" android_src="@drawable/right_icon" /> Open the MainActivity.java file in the wear module. In the onCreate() method, delete all lines after the line setContentView(R.layout.activity_main);. Now, run the app on both square and round emulators. As we can see, the BoxInsetLayout does a fine job of inflating our layout regardless of screen shape. How it works is very simple. The BoxInsetLayout creates a square region, that is as large as can fit inside the circle of a round screen. This is set with the app:layout_box="all" instruction, which can also be used for positioning components, as we will see in a minute. We have also set the padding of the BoxInsetLayout to 15 dp and that of the FrameLayout to 5 dp. This has the effect of a margin of 5 dp on round screens and 15 dp on square ones. Whether you use the WatchViewStub and create separate layouts for each screen shape or BoxInsetLayout and just one layout file depends entirely on your preference and the purpose and design of your app. Whichever method you choose, you will no doubt want to add Material Design elements to your wearable app, the most common and versatile of these being the card. In the following section, we will explore the two ways that we can do this, the CardScrollView and the CardFragment. Adding cards The CardFragment class provides a default card view, providing two text views and an image. It is beautifully simple to set up, has all the Material Design features such as rounded corners and a shadow, and is suitable for nearly all purposes. It can be customized, as we will see, although the CardScrollView is often a better option. First, let us see, how to implement a default card for wearables: Open the activity_main.xml file in the wear module of the current project. Delete or comment out the the text view and two image views. Open the MainActivity.java file in the wear module. In the onCreate() method, add the following code: FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); CardFragment cardFragment = CardFragment.create("Short title", "with a longer description"); fragmentTransaction.add(R.id.wearable_layout, cardFragment); fragmentTransaction.commit(); Run the app on one or other of the wearable emulators to see how the default card looks. The way we created the CardFragment itself, is also very straightforward. We used two string parameters here, but there is a third, drawable parameter and if the line is changed to CardFragment cardFragment = CardFragment.create("TITLE", "with description and drawable", R.drawable.left_icon); then we will get the following output: This default implementation for cards on wearable is fine for most purposes and it can be customized by overriding its onCreateContentView() method. However, the CardScrollView is a very handy alternative, and this is what we will look at next. Customizing cards The CardScrollView is defined from within our layout and furthermore it detects screen shape and adjusts the margins to suit each shape. To see how this is done, follow these steps: Open the activity_main.xml file in the wear module. Delete or comment out every element, except the root BoxInsetLayout. Place the following CardScrollView inside the BoxInsetLayout: <android.support.wearable.view.CardScrollView android_id="@+id/card_scroll_view" android_layout_height="match_parent" android_layout_width="match_parent" app_layout_box="bottom"> </android.support.wearable.view.CardScrollView> Inside this, add this CardFrame: <android.support.wearable.view.CardFrame android_layout_width="match_parent" android_layout_height="wrap_content"> </android.support.wearable.view.CardFrame> Inside the CardFrame, add a LinearLayout. Add some views to this, so that the preview resembles the layout here: Open the MainActivity.java file. Replace the code we added to the onCreate() method with this: CardScrollView cardScrollView = (CardScrollView) findViewById(R.id.card_scroll_view); cardScrollView.setCardGravity(Gravity.BOTTOM); You can now test the app on an emulator, which will produce the following result: As can be seen in the previous image, the Android Studio has preview screens for both wearable shapes. Like some other previews, these are not always what you will see on a device, but they allow us to put layouts together very quickly, by dragging and dropping widgets. As we can see, the CardScrollView and CardFrame are even easier to implement than the CardFragment and also far more flexible, as we can design almost any layout we can imagine. We assigned app:layout_box here again, only this time using bottom, causing the card to be placed as low on the screen as possible. It is very important, when designing for such small screens, to keep our layouts as clean and simple as possible. Google's design principles state that wearable apps should be glanceable. This means that, as with a traditional wrist watch, the user should be able to glance at our app and immediately take in the information and return to what they were doing. Another of Google's design principle—Zero to low interaction—is only a single tap or swipe a user needs to do to interact with our app. With these principles in mind, let us create a small app, with some actual functionality. In the next section, we will take advantage of the new heart rate sensor found in many wearable devices and display current beats-per-minute on the display. Accessing sensor data The location of an Android Wear device on the user's wrist, makes it the perfect piece of hardware for fitness apps, and not surprisingly, these apps are immensely popular. As with most features of the SDK, accessing sensors is pleasantly simple, using classes such as managers and listeners and requiring only a few lines of code, as you will see by following these steps: Open the project we have been working on in this article. Replace the background image with one that might be suitable for a fitness app. I have used a simple image of a heart. Open the activity_main.xml file. Delete everything, except the root BoxInsetLayout. Place this TextView inside it: <TextView android_id="@+id/text_view" android_layout_width="match_parent" android_layout_height="wrap_content" android_layout_gravity="center_vertical" android_gravity="center" android_text="BPM" android_textColor="@color/black" android_textSize="42sp" /> Open the Manifest file in the wear module. Add the following permission inside the root manifest node: <uses-permission android_name="android.permission.BODY_SENSORS" /> Open the MainActivity.java file in the wear module. Add the following fields: private TextView textView; private SensorManager sensorManager; private Sensor sensor; Implement a SensorEventListener on the Activity: public class MainActivity extends Activity implements SensorEventListener { Implement the two methods required by the listener. Edit the onCreate() method, like this: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text_view); sensorManager = ((SensorManager) getSystemService(SENSOR_SERVICE)); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE); } Add this onResume() method: protected void onResume() { super.onResume(); sensorManager.registerListener(this, this.sensor, 3); } And this onPause() method: @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } Edit the onSensorChanged() callback, like so: @Override public void onSensorChanged(SensorEvent event) { textView.setText("" + (int) event.values[0]); } If you do not have access to a real device, you can download a sensor simulator from here:     https://code.google.com/p/openintents/wiki/SensorSimulator The app is now ready to test. We began by adding a permission in the AndroidManifest.xml file in the appropriate module; this is something we have done before and need to do any time we are using features, that require the user's permission before installing. The inclusion of a background image may seem necessary, but an appropriate background is a real aid to glancability as the user can tell instantly which app they are looking at. It should be clear, from the way the SensorManager and the Sensor are set up in the onCreate() method, that all sensors are accessed in the same way and different sensors can be accessed with different constants. We used TYPE_HEART_RATE here, but any other sensor can be started with the appropriate constant, and all sensors can be managed with the same basic structures as we found here, the only real difference being the way each sensor returns SensorEvent.values[]. A comprehensive list of all sensors, and descriptions of the values they produce can be found at http://developer.android.com/reference/android/hardware/Sensor.html. As with any time our apps utilize functions that run in the background, it is vital that we unregister our listeners, whenever they are no longer needed, in our Activity's onPause() method. We didn't use the onAccuracyChanged() callback here, but its purpose should be clear and there are many possible apps where its use is essential. This concludes our exploration of wearable apps and how they are put together. Such devices continue to become more prevalent and the possibility of ever more imaginative uses is endless. Providing we consider why and how people use smart watches, and the like, and develop to take advantage of the location of these devices by programming glanceable interfaces that require the minimum of interactivity, Android Wear seems certain to grow in popularity and use, and the developers will continue to produce ever more innovative apps. Summary In this article, we have explored Android wearable apps and how they are put together. Despite their diminutive size and functionality, wearables offer us an enormous range of possibilities. We know now how to create and connect wearable AVDs and how to develop easily for both square and round devices. We then designed the user interface for both round and square screens. To learn more about Android UI interface designing and developing android applications, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended: Android User Interface Development: Beginner's Guide, found at https://www.packtpub.com/application-development/android-user-interface-development-beginners-guide Android 4: New Features for Application Development, found at https://www.packtpub.com/application-development/android-4-new-features-application-development Resources for Article: Further resources on this subject: Understanding Material Design [Article] Speaking Java – Your First Game [Article] Mobile Game Design Best Practices [Article]
Read more
  • 0
  • 0
  • 4134

article-image-creating-grids-panels-and-other-widgets
Packt
10 Feb 2016
6 min read
Save for later

Creating Grids, Panels, and other Widgets

Packt
10 Feb 2016
6 min read
In this article by Raymond Camden, author of the book jQuery Mobile Web Development Essentials – Third Edition, we will look at dialogs, grids, and other widgets. While jQuery mobile provides great support for them, you get even more UI controls within the framework. In this article, we will see how to layout content with grids and make responsive grids. (For more resources related to this topic, see here.) Laying out content with grids Grids are one of the few features of jQuery mobile that do not make use of particular data attributes. Instead, you work with grids simply by specifying CSS classes for your content. Grids come in four flavors: two-column, three-column, four-column, and five-column grids. You will probably not want to use the five-column one on a phone device. Save that for a tablet instead. You begin a grid with a div block that makes use of the class ui-grid-X, where X will either be a, b, c, or d. ui-grid-a represents a two-column grid. The ui-grid-b class is a three-column grid. You can probably guess what c and d create. So, to begin a two-column grid, you would wrap your content with the following: <div class="ui-grid-a">   Content </div> Within the div tag, you then use div for each cell of the content. The class for grid calls begins with ui-block-X, where X goes from a to d. The ui-block-a class would be used for the first cell, ui-block-b for the next, and so on. This works much like the HTML tables. Putting it together, the following code snippet demonstrates a simple two-column grid with two cells of content: <div class="ui-grid-a">   <div class="ui-block-a">Left</div>   <div class="ui-block-b">Right</div> </div> The text within a cell will automatically wrap. Listing 7-1 demonstrates a simple grid with a large amount of text in one of the columns:   In the mobile browser, you can clearly see the two columns: If the text in these divs seems a bit close together, there is a simple fix for that. In order to add a bit more space between the content of the grid cells, you can add a class to your main div that specifies ui-content. This tells jQuery mobile to pad the content a bit. For example: <div class="ui-grid-a ui-content"> This small change modifies the previous screenshot like the following: Listing 7-1: test1.html <div data-role="page" id="first">       <div data-role="header">         <h1>Grid Test</h1>       </div>       <div role="main" class="ui-content">         <div class="ui-grid-a">           <div class="ui-block-a">           <p>           This is my left hand content. There won't be a lot of           it.           </p>           </div>           <div class="ui-block-b">             <p>               This is my right hand content. I'm going to fill it               with some dummy text.             </p>             <p>               Bacon ipsum dolor sit amet andouille capicola spare               ribs, short loin venison sausage prosciutto               turkey flank frankfurter pork belly short ribs.               chop, pancetta turkey bacon short ribs ham flank               pork belly. Tongue strip steak short ribs tail           </p>           </div>         </div>       </div>     </div> Working with other types of grids then is simply a matter of switching to the other classes. For example, a four-column grid would be set up similar to the following code snippet: <div class="ui-grid-c">   <div class="ui-block-a">1st cell</div>   <div class="ui-block-b">2nd cell</div>   <div class="ui-block-c">3rd cell</div> </div> Again, keep in mind your target audience. Anything over two columns may be too thin on a mobile phone. To create multiple rows in a grid, you need to simply repeat the blocks. The following code snippet demonstrates a simple example of a grid with two rows of cells: <div class="ui-grid-a">   <div class="ui-block-a">Left Top</div>   <div class="ui-block-b">Right Top</div>   <div class="ui-block-a">Left Bottom</div>   <div class="ui-block-b">Right Bottom</div> </div> Notice that there isn't any concept of a row. jQuery mobile handles knowing that it should create a new row when the block starts over with the one marked ui-block-a. The following code snippet, Listing 7-2, is a simple example: Listing 7-2:test2.html <div data-role="page" id="first">       <div data-role="header">         <h1>Grid Test</h1>       </div>       <div role="main" class="ui-content">         <div class="ui-grid-a">           <div class="ui-block-a">             <p>               <img src="ray.png">             </p>           </div>           <div class="ui-block-b">           <p>           This is Raymond Camden. Here is some text about him. It           may wrap or it may not but jQuery Mobile will make it          look good. Unlike Ray!           </p>           </div>           <div class="ui-block-a">             <p>               This is Scott Stroz. Scott Stroz is a guy who plays               golf and is really good at FPS video games.             </p>           </div>           <div class="ui-block-b">             <p>               <img src="scott.png">             </p>           </div>         </div>       </div>     </div> The following screenshot shows the result: Making responsive grids Earlier we mentioned that complex grids may not work depending on the size or your targeted devices. A simple two-column grid is fine, but the larger grids would render well on tablets only. Luckily, there's a simple solution for it. jQuery mobile's latest updates include much better support for responsive design. Let's consider a simple example. Here is a screenshot of a web page using a four-column grid: It is readable for sure, but it is a bit dense. By making use of responsive design, we could handle the different sizes intelligently using the same basic HTML. jQuery mobile enables a simple solution for this by adding the class ui-responsive to an existing grid. Here is an example: <div class="ui-grid-c ui-responsive"> By making this one small change, look how the phone version of our page changes: The four-column layout now is a one-column layout instead. If viewed in a tablet, the original four-column design will be preserved. Summary In this article, you learned more about how jQuery mobile enhances basic HTML to provide additional layout controls to our mobile pages. With grids, you learned a new way to easily layout content in columns. Resources for Article:   Further resources on this subject: Classes and Instances of Ember Object Model [article] Introduction to Akka [article] CoreOS Networking and Flannel Internals [article]
Read more
  • 0
  • 0
  • 1221
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-introduction-sql-and-sqlite
Packt
10 Feb 2016
22 min read
Save for later

Introduction to SQL and SQLite

Packt
10 Feb 2016
22 min read
In this article by Gene Da Rocha, author or the book Learning SQLite for iOS we are introduced to the background of the Structured Query Language (SQL) and the mobile database SQLite. Whether you are an experienced technologist at SQL or a novice, using the book will be a great aid to help you understand this cool subject, which is gaining momentum. SQLite is the database used on the mobile smartphone or tablet that is local to the device. SQLite has been modified by different vendors to harden and secure it for a variety of uses and applications. (For more resources related to this topic, see here.) SQLite was released in 2000 and has grown to be as a defacto database on a mobile or smartphone today. It is an open source piece of software with a low footprint or overhead, which is packaged with a relational database management system. Mr D. Richard Hipp is the inventor and author for SQLite, which was designed and developed on a battleship while he was at a company called General Dynamics at the U. S. Navy. The programming was built for a HP-UX operating system with Informix as the database engine. It took many hours in the data to upgrade or install the database software and was an over-the-top database for this experience DBA (database administrator). Mr Hipp wanted a portable, self-contained, easy-to-use database, which could be mobile, quick to install, and not dependent on the operating. Initially, SQLite 1.0 used the gdbm as its storage system, but later, it was replaced with its own B-tree implementation and technology for the database. The B-tree implementation was enhanced to support transactions and store rows of data with key order. By 2001 onwards, open source family extensions for other languages, such as Java, Python, and Perl, were written to support their applications. The database and its popularity within the open source community and others were growing. Originally based upon relational algebra and tuple relational calculus, SQL consists of a data definition and manipulation language. The scope of SQL includes data insert, query, update and delete, schema creation and modification, and data access control. Although SQL is often described as, and to a great extent is, a declarative language (4GL), it also includes procedural elements. Internationalization supported UTF-16 and UTF-8 and included text-collating sequences in version 2 and 3 in 2004. It was supported by funding from AOL (America Online) in 2004. It works with a variety of browsers, which sometimes have in-built support for this technology. For example, there are so many extensions that use Chrome or Firefox, which allow you to manage the database. There have been many features added to this product. The future with the growth in mobile phones sets this quick and easy relational database system to quantum leap its use within the mobile and tablet application space. SQLite is based on the PostgreSQL as a point of reference. SQLite does not enforce any type checking. The schema does not constrain it since the type of value is dynamic, and a trigger will be activated by converting the data type. About SQL In June 1970, a research paper was published by Dr. E.F. Codd called A Relational Model of Data for Large Shared Data Banks. The Association of Computer Machinery (ACM) accepted Codd data and technology model, which has today become the standard for the RDBMS (Relational Database Management System). IBM Corporation had invented the language called by Structured English Query Language (SEQUEL), where the word "English" was dropped to become SQL. SQL is still pronounced as what has today become the standard for the RDBMS (Relational Database Management System) had a product called which has today become the SQL technology, followed by Oracle, Sybase and Microsoft's SQL Server. The standard commercial relational database management system language today is SQL (SEQUEL). Today, there are ANSI standards for SQL, and there are many variations of this technology. Among the mentioned manufacturers, there are also others available in the open source world, for example, an SQL query engine such as Presto. This is the distribution engine for SQL under open source, which is made to execute interactive analytic queries. Presto queries are run under databases from a variety of data source sizes—gigabytes to petabytes. Companies such as Facebook and Dropbox use the Presto SQL engine for their queries and analytics in data warehouse and related applications. SQL is made up of a data manipulation and definition language built with tuple and algebra calculation in a relational format. The SQL language has a variety of statements but most would recognize the INSERT, SELECT, UPDATE and DELETE statements. These statements form a part of the database schema management process and aid the data access and security access. SQL includes procedural elements as part of its setup. Is SQLite used anywhere? Companies may use applications but they are not aware of the SQL engines that drive their data storage and information. Although, it has become a standard with the American National Standards Institute (ANSI) in 1986, SQL features and functionality are not 100% portable among different SQL systems and require code changes to be useful. These standards are always up for revision to ensure ANSI is maintained. There are many variants of SQL engines on the market from companies, such as Oracle, SQL Server (Microsoft), DB2 (IBM), Sybase (SAP), MYSQL (Oracle), and others. Different companies operate several types of pricing structures, such as free open source, or a paid per seat or by transactions or server types or loads. Today, there is a preference for using server technology and SQL in the cloud with different providers, for example, Amazon Web Services (AWS). SQLite, as it names suggests, is SQL in a light environment, which is also flexible and versatile. Enveloped and embedded database among other processes SQLite has been designed and developed to work and coexist with other applications and processes in its area. RDBMS is tightly integrated with the native application software, which requires storing information but is masked and hidden from users, and it requires minimal administration or maintenance. SQLite can work with different API hidden from users and requires minimal administration or maintenance areas. RDBMS is intertwined with other applications; that is, it requires minimal supervision; there is no network traffic; no network access conflicts or configuration; no access limitations with privileges or permissions; and a large reduced overhead. These make it easier and quicker to deploy your applications to the app stores or other locations. The different components work seamlessly together in a harmonized way to link up data with the SQLite library and other processes. These show how the Apache process and the C/C++ process work together with the SQLite-C library to interface and link with it so that it becomes seamless and integrates with the operating system. SQLite has been developed and integrated in such a way that it will interface and gel with a variety of applications and multiple solutions. As a lightweight RDBMS, it can stand on its own by its versatility and is not cumbersome or too complex to benefit your application. It can be used on many platforms and comes with a binary compatible format, which is easier to dovetail within your mobile application. The different types of I.T. professionals will be involved with SQLite since it holds the data, affects performance, and involves database design, user or mobile interface design specialists, analysts and consultancy types. These professionals could use their previous knowledge of SQL to quickly grasp SQLite. SQLite can act as both data processor for information or deal with data in memory to perform well. The different software pieces of a jigsaw can interface properly by using the C API interface to SQLite, which some another programming language code. For example, C or C++ code can be programmed to communicate with the SQLITE C API, which will then talk to the operating system, and thus communicate with the database engine. Another language such as PHP can communicate using its own language data objects, which will in turn communicate with the SQLite C API and the database. SQLite is a great database to learn especially for computer scientists who want to use a tool that can open your mind to investigate caching, B-Tree structures and algorithms, database design architecture, and other concepts. The architecture of the SQLite database As a library within the OS-Interface, SQLite will have many functions implemented through a programming called tclsqlite.c. Since many technologies and reserved words are used, to language, and in this case, it will have the C language. The core functions are to be found in main.c, legacy.c, and vmbeapi.c. There is also a source code file in C for the TCL language to avoid any confusion; the prefix of sqlite3 is used at the beginning within the SQLite library. The Tokeniser code base is found within tokenize.c. Its task is to look at strings that are passed to it and partition or separate them into tokens, which are then passed to the parser. The Parser code base is found within parse.y. The Lemon LALR(1) parser generator is the parser for SQLite; it uses the context of tokens and assigns them a meaning. To keep within the low-sized footprint of RDBMS, only one C file is used for the parse generator. The Code Generator is then used to create SQL statements from the outputted tokens of the parser. It will produce virtual machine code that will carry out the work of the SQL statements. Several files such as attach.c, build.c, delete.c, select.c, and update.c will handle the SQL statements and syntax. Virtual machine executes the code that is generated from the Code Generator. It has in-built storage where each instruction may have up to three additional operands as a part of each code. The source file is called vdbe.c, which is a part of the SQLite database library. Built-in is also a computing engine, which has been specially created to integrate with the database system. There are two header files for virtual machine; the header files that interface a link between the SQLite libraries are vdbe.h and vdbeaux.c, which have utilities used by other modules. The vdbeapi.c file also connects to virtual machine with sqlite_bind and other related interfaces. The C language routines are called from the SQL functions that reference them. For example, functions such as count() are defined in func.c and date functions are located in date.c. B-tree is the type of table implementation used in SQLite; and the C source file is btree.c. The btree.h header file defines the interface to the B-tree system. There is a different B-tree setup for every table and index and held within the same file. There is a header portion within the btree.c, which will have details of the B-tree in a large comment field. The Pager or Page Cache using the B-tree will ask for data in a fixed sized format. The default size is 1024 bytes, which can be between 512 and 65536 bytes. Commit and Rollback operations, coupled with the caching, reading, and writing of data are handled by Page Cache or Pager. Data locking mechanisms are also handled by the Page Cache. The C file page.c is implemented to handle requests within the SQLite library and the header file is pager.h. The OS Interface C file is defined in os.h. It addresses how SQLite can be used on different operating systems and become transparent and portable to the user thus, becoming a valuable solution for any developer. An abstract layer to handle Win32 and POSIX compliant systems is also in place. Different operating systems have their own C file. For example, os_win.c is for Windows, os_unix.c is for Unix, coupled with their own os_win.h and os_unix.h header files. Util.c is the C file that will handle memory allocation and string comparisons. The Utf.c C file will hold the Unicode conversion subroutines. The Utf.c C file will hold the Unicode data, sort it within the SQL engine, and use the engine itself as a mechanism for computing data. Since the memory of the device is limited and the database size has the same constraints, the developer has to think outside the box to use these techniques. These types of memory and resource management form a part of the approach when the overlay techniques were used in the past when disk and memory was limited.   SELECT parameter1, STTDEV(parameter2)       FROM Table1 Group by parameter1       HAVING parameter1 > MAX(parameter3) IFeatures As part of its standards, SQLite uses and implements most of the SQL-92 standards, but not all the potential features or parts of functionality are used or realized. For example, the SQLite uses and implements most of the SQL-92 standards but not all potent columns. The support for triggers is not 100% as it cannot write output to views, but as a substitute, the INSTEAD OF statement can be used. As mentioned previously, the use of a type for a column is different; most relational database systems assign them to individual values. SQLite will convert a string into an integer if the columns preferred type is an integer. It is a good piece of functionality when bound to this type of scripting language, but the technique is not portable to other RDBMS systems. It also has its criticisms for not having a good data integrity mechanism compared to others in relation to statically typed columns. As mentioned previously, it has many bindings to many languages, such as Basic, C, C#, C++, D, Java, JavaScript, Lua, PHP, Objective-C, Python, Ruby, and TCL. Its popularity by the open source community and its usage by customers and developers have enabled its growth to continue. This lightweight RDBMS can be used on Google Chrome, Firefox, Safari, Opera, and the Android Browsers and has middleware support using ADO.NET, ODBC, COM (ActiveX), and XULRunner. It also has the support for web application frameworks such as Django (Python-based), Ruby on Rails, and Bugzilla (Mozilla). There are other applications such as Adobe Photoshop Light, which uses SQLite and Skype. It is also part of the Windows 8, Symbian OS, Android, and OpenBSD operating. Apple also included it via API support via OSXvia OSXother applications like Adobe Photoshop Light. Apart from not having the large overhead of other database engines, SQLite has some major enhancements such as the EXPLAIN keyword with its manifest typing. To control constraint conflicts, the REPLACE and ON CONFLICT statements are used. Within the same query, multiple independent databases can be accessed using the DETACH and ATTACH statements. New SQL functions and collating sequences can be created using the predefined API's, which offer much more flexibility. As there is no configuration required, SQLite just does the job and works. There is no need to initialize, stop, restart, or start server processes and no administrator is required to create the database with proper access control or security permits. After any failure, no user actions are required to recover the database since it is self-repairing: SQLite is more advanced than is thought of in the first place. Unlike other RDBMS, it does not require a server setup via a server to serve up data or incur network traffic costs. There are no TCP/IP calls and frequent communication backwards or forwards. SQLite is direct; the operating system process will deal with database access to its file; and control database writes and reads with no middle-man process handshaking. By having no server backend, the process of installation, configuration, or administration is reduced significantly and the access to the database is granted to programs that require this type of data operations. This is an advantage in one way but is also a disadvantage for security and protection from data-driven misuse and data concurrency or data row locking mechanisms. It also allows the database to be accessed several times by different applications at the same time. It supports a form of portability for the cross-platform database file that can be located with the database file structure. The database file can be updated on one system and copied to another on either 32 bit or 64 bit with different architectures. This does not make a difference to SQLite. The usage of different architecture and the promises of developers to keep the file system stable and compatible with the previous, current, and future developments will allow this database to grow and thrive. SQLite databases don't need to upload old data to the new formatted and upgraded databases; it just works. By having a single disk file for the database, the information can be copied on a USB and shared or just reused on another device very quickly keeping all the information intact. Other RDBMS single-disk file for the database; the information can be copied on a USB and shared or just reused on another device very quickly keeping all the information in tact to grow and thrive. Another feature of this portable database is its size, which can start on a single 512-byte page and expand to 2147483646 pages at 65536 bytes per page or in bytes 140,737,488,224,256, which equates to about 140 terabytes. Most other RDBMS are much larger, but IBM's Cloudscape is small with a 2MB jar file. It is still larger than SQLite. The Firebird alternative's client (frontend) library is about 350KB, whereas the Berkeley Oracle database is around 450kb without SQL support and with one simple key/value pair's option. This advanced portable database system and its source code is in the public domain. They have no copyright or any claim on the source code. However, there are open source license issues and controls for some test code and documentation. This is great news for developers who might want to code up new extensions or database functionality that works with their programs, which could be made into a 'product extension' for SQLite. You cannot have this sort of access to SQL source code around since everything has a patent, limited access, or just no access. There are signed affidavits by developers to disown any copyright interest in the SQLite code. SQLite is different, because it is just not governed or ruled by copyright law; the way software should really work or it used. There are signed affidavits by developers to disown any copyright interest in the SQLite code. This means that you can define a column with a datatype of integer, but its property is dictated by the inputted values and not the column itself. This can allow any value to be stored in any declared data type for this column with the exception of an integer primary key. This feature would suit TCL or Python, which are dynamically typed programming languages. When you allocate space in most RDBMS in any declared char(50), the database system will allocate the full 50 bytes of disk space even if you do not allocate the full 50 bytes of disk space. So, out of char(50) sized column, three characters were used, then the disk space would be only three characters plus two for overhead including data type, length but not 50 characters such as other database engines. This type of operation would reduce disk space usage and use only what space was required. By using the small allocation with variable length records, the applications runs faster, the database access is quicker, manifest typing can be used, and the database is small and nimble. The ease of using this RDBMS makes it easier for most programmers at an intermediate level to create applications using this technology with its detailed documentation and examples. Other RDBMS are internally complex with links to data structures and objects. SQLite comprises using a virtual machine language that uses the EXPLAIN reserved word in front of a query. Virtual machine has increased and benefitted this database engine by providing an excellent process or controlled environment between back end (where the results are computed and outputted) and the front end (where the SQL is parsed and executed). The SQL implementation language is comparable to other RDBMS especially with its lightweight base; it does support recursive triggers and requires the FOR EACH row behavior. The FOR EACH statement is not currently supported, but functionality cannot be ruled out in the future. There is a complete ALTER TABLE support with some exceptions. For example, the RENAME TABLE, ADD COLUMN, or ALTER COLUMN is supported, but the DROP COLUMN, ADD CONSTRAINT, or ALTER COLUMN is not supported. Again, this functionality cannot be ruled out in the future. The RIGHT OUTER JOIN and FULL OUTER JOIN are not support, but the RIGHT OUTER JOIN, FULL OUTER JOIN, and LEFT OUTER JOIN are implemented. The views within this RDBMS are read only. As described so far in the this article, SQLite is a nimble and easy way to use database that developers can engage with quickly, use existing skills, and output systems to mobile devices and tablets far simpler than ever before. With the advantage of today's HTML5 and other JavaScript frameworks, the advancement of SQL and the number of SQLite installations will quantum leap. Working with SQLite The website for SQLite is www.sqlite.org where you can download all the binaries for the database, documentation, and source code, which works on operating systems such as Linux, Windows and MAC OS X. The SQLite share library or DLL is the library to be used for the Windows operating system and can be installed or seen via Visual Studio with the C++ language. So, the developer can write the code using the library that is presently linked in reference via the application. When execution has taken place, the DLL will load and all references in the code will link to those in the DLL at the right time. The SQLite3 command-line program, CLP, is a self-contained program that has all the components built in for you to run at the command line. It also comes with an extension for TCL. So within TCL, you can connect and update the SQLite database. SQLite downloads come with the TAR version for Unix systems and the ZIP version for Windows systems. iOS with SQLite On the hundreds of thousands of apps on all the app stores, it would be difficult to find the one that does not require a database of some sort to store or handle data in a particular way. There are different formats of data called datafeeds, but they all require some temporary or permanent storage. Small amounts of data may not be applicable but medium or large amounts of data will require a storage mechanism such as a database to assist the app. Using SQLite with iOS will enable developers to use their existing skills to run their DBMS on this platform as well. For SQLite, there is the C-library that is embedded and available to use with iOS with the Xcode IDE. Apple fully supports SQLite, which uses an include statement as a part of the library call, but there is not easy made mechanism to engage. Developers also tend to use FMDB—a cocoa/objective-C wrapper around SQLite. As SQLite is fast and lightweight, its usage of existing SQL knowledge is reliable and supported by Apple on Mac OS and iOS and support from many developers as well as being integrated without much outside involvement. The third SQLite library is under the general tab once the main project name is highlighted on the left-hand side. Then, at the bottom of the page or within the 'Linked Frameworks and Library', click + and a modal window appears. Enter the word sqlite and select sqlite; then, select the libsqlite3.dylib library. This one way to set up the environment to get going. In effect, it is the C++ wrapper called the libsqlite3.dylib library within the framework section, which allows the API to work with the SQLite commands. The way in which a text file is created in iOS is the way SQLite will be created. It will use the location (document directory) to save the file that is the one used by iOS. Before anything can happen, the database must be opened and ready for querying and upon the success of data, the constant SQLITE_OK is set to 0. In order to create a table in the SQLite table using the iOS connection and API, the method sqlite3_exec is set up to work with the open sqlite3 object and the create table SQL statement with a callback function. When the callback function is executed and a status is returned of SQLITE_OK, it is successful; otherwise, the other constant SQLITE_ERROR is set to 1. Once the C++ wrapper is used and the access to SQLite commands are available, it is an easier process to use SQLite with iOS. Summary In this article, you read the history of SQL, the impact of relational databases, and the use of a mobile SQL database namely SQLite. It outlines the history and beginnings of SQLite and how it has grown to be the most used database on mobile devices so far. Resources for Article:   Further resources on this subject: Team Project Setup [article] Introducing Sails.js [article] Advanced Fetching [article]
Read more
  • 0
  • 0
  • 4003

article-image-payment-processing-workflow
Packt
09 Feb 2016
4 min read
Save for later

Payment Processing Workflow

Packt
09 Feb 2016
4 min read
In this article by Ernest Bruce, author of the book, Apply Pay Essentials, the author talks about actors and operations in the payment processing workflow. After the user authorizes the payment request, the user app, the payment gateway, and the order processing web app team up to securely deliver the payment information to the issuing bank, to transfer the funds form the user's account to the acquiring bank, and to inform the user of the transaction status (approved or declined). (For more resources related to this topic, see here.) The payment processing workflow is made up of three phases: Preprocess phase: This is the phase where the app gets a charge token from the payment gateway, and it sends order information (including the charge token) to the order-processing server Process phase: This is the phase where the order-processing web app (running on your server) charges the user's card through the payment gateway, updates order and inventory data if the charge is successful, and sends the transaction status to the user app Postprocess phase: This is the phase where the user app informs the user about the status of the transaction and dismisses the payment sheet As, in general, the payment-gateway API does not run appropriately in the Simulator app, you must use an actual iOS device to test the payment-processing workflow in your development environment. In addition to this, you need either a separate computer to run the order-processing web app or a proxy server that intercepts network traffic from the device and redirects the appropriate requests to your development computer. For details, see the documentation for the example project. Actors and Operations in the Processing Workflow The payment processing workflow is the process by which the payment information that is generated by Apple Pay from the payment request and the information that the user entered in the payment sheet is transmitted to your payment gateway and the card's issuing bank to charge the card and make the payment's funds available in your acquiring bank. The workflow starts when the payment sheet calls the paymentAuthorizationViewController:didAuthorizePayment:completion: delegate method, providing the user app general order information (such as shipping and billing information) and a payment token containing encrypted-payment data. This diagram depicts the actors, operations, and data that are part of the payment processing workflow: Payment_processing_workflow These are the operations and data that are part of the workflow: payment authorized: This is when the payment sheet tells the app that the user authorized the payment payment token: This is when the app provides the payment token to the payment gateway, which returns a charge token order info and charge token: This is when the app sends information about the order and the charge token to the order processing web app charge card: This is when the web app charges the card through the payment gateway approved or declined: This is when the payment gateway tells the web app whether the payment is approved or declined transaction result and order metadata: This is when the web app provides the user app the result of the transaction and order information, such as the order number transaction result: This is when the app tells the payment sheet the result of the payment transaction: approved, or declined payment sheet done: This is when the payment sheet tells the app that the transaction is complete dismiss: This is when the app dismisses the payment sheet Summary You can also check out the following books on Apple: Mastering Apple Aperture, Thomas Fitzgerald by Packt Publishing Apple Motion 5 Cookbook, Nick Harauz, by Packt Publishing Resources for Article: Further resources on this subject: BatteryMonitor Application [article] Introducing Xcode Tools for iPhone Development [article] Network Development with Swift [article]
Read more
  • 0
  • 0
  • 4601

article-image-creating-mutable-and-immutable-classes-swift
Packt
20 Jan 2016
8 min read
Save for later

Creating Mutable and Immutable Classes in Swift

Packt
20 Jan 2016
8 min read
In this article by Gastón Hillar, author of the book Object-Oriented Programming with Swift, we will learn how to create mutable and immutable classes in Swift. (For more resources related to this topic, see here.) Creating mutable classes So far, we worked with different type of properties. When we declare stored instance properties with the var keyword, we create a mutable instance property, which means that we can change their values for each new instance we create. When we create an instance of a class that defines many public-stored properties, we create a mutable object, which is an object that can change its state. For example, let's think about a class named MutableVector3D that represents a mutable 3D vector with three public-stored properties: x, y, and z. We can create a new MutableVector3D instance and initialize the x, y, and z attributes. Then, we can call the sum method with the delta values for x, y, and z as arguments. The delta values specify the difference between the existing and new or desired value. So, for example, if we specify a positive value of 30 in the deltaX parameter, it means we want to add 30 to the X value. The following lines declare the MutableVector3D class that represents the mutable version of a 3D vector in Swift: public class MutableVector3D { public var x: Float public var y: Float public var z: Float init(x: Float, y: Float, z: Float) { self.x = x self.y = y self.z = z } public func sum(deltaX: Float, deltaY: Float, deltaZ: Float) { x += deltaX y += deltaY z += deltaZ } public func printValues() { print("X: (self.x), Y: (self.y), Z: (self.z))") } } Note that the declaration of the sum instance method uses the func keyword, specifies the arguments with their types enclosed in parentheses, and then declares the body for the method enclosed in curly brackets. The public sum instance method receives the delta values for x, y, and z (deltaX, deltaY and deltaZ) and mutates the object, which means that the method changes the values of x, y, and z. The public printValues method prints the values of the three instance-stored properties: x, y, and z. The following lines create a new MutableVector3D instance method called myMutableVector, initialized with the values for the x, y, and z properties. Then, the code calls the sum method with the delta values for x, y, and z as arguments and finally calls the printValues method to check the new values after the object mutated with the call to the sum method: var myMutableVector = MutableVector3D(x: 30, y: 50, z: 70) myMutableVector.sum(20, deltaY: 30, deltaZ: 15) myMutableVector.printValues() The results of the execution in the Playground are shown in the following screenshot: The initial values for the myMutableVector fields are 30 for x, 50 for y, and 70 for z. The sum method changes the values of the three instance-stored properties; therefore, the object state mutates as follows: myMutableVector.X mutates from 30 to 30 + 20 = 50 myMutableVector.Y mutates from 50 to 50 + 30 = 80 myMutableVector.Z mutates from 70 to 70 + 15 = 85 The values for the myMutableVector fields after the call to the sum method are 50 for x, 80 for y, and 85 for z. We can say that the method mutated the object's state; therefore, myMutableVector is a mutable object and an instance of a mutable class. It's a very common requirement to generate a 3D vector with all the values initialized to 0—that is, x = 0, y = 0, and z = 0. A 3D vector with these values is known as an origin vector. We can add a type method to the MutableVector3D class named originVector to generate a new instance of the class initialized with all the values in 0. Type methods are also known as class or static methods in other object-oriented programming languages. It is necessary to add the class keyword before the func keyword to generate a type method instead of an instance. The following lines define the originVector type method: public class func originVector() -> MutableVector3D { return MutableVector3D(x: 0, y: 0, z: 0) } The preceding method returns a new instance of the MutableVector3D class with 0 as the initial value for all the three elements. The following lines call the originVector type method to generate a 3D vector, the sum method for the generated instance, and finally, the printValues method to check the values for the three elements on the Playground: var myMutableVector2 = MutableVector3D.originVector() myMutableVector2.sum(5, deltaY: 10, deltaZ: 15) myMutableVector2.printValues() The following screenshot shows the results of executing the preceding code in the Playground: Creating immutable classes Mutability is very important in object-oriented programming. In fact, whenever we expose mutable properties, we create a class that will generate mutable instances. However, sometimes a mutable object can become a problem and in certain situations, we want to avoid the objects to change their state. For example, when we work with concurrent code, an object that cannot change its state solves many concurrency problems and avoids potential bugs. For example, we can create an immutable version of the previous MutableVector3D class to represent an immutable 3D vector. The new ImmutableVector3D class has three immutable instance properties declared with the let keyword instead of the previously used var[SI1]  keyword: x, y, and z. We can create a new ImmutableVector3D instance and initialize the immutable instance properties. Then, we can call the sum method with the delta values for x, y, and z as arguments. The sum public instance method receives the delta values for x, y, and z (deltaX, deltaY, and deltaZ), and returns a new instance of the same class with the values of x, y, and z initialized with the results of the sum. The following lines show the code of the ImmutableVector3D class: public class ImmutableVector3D { public let x: Float public let y: Float public let z: Float init(x: Float, y: Float, z: Float) { self.x = x self.y = y self.z = z } public func sum(deltaX: Float, deltaY: Float, deltaZ: Float) -> ImmutableVector3D { return ImmutableVector3D(x: x + deltaX, y: y + deltaY, z: z + deltaZ) } public func printValues() { print("X: (self.x), Y: (self.y), Z: (self.z))") } public class func equalElementsVector(initialValue: Float) -> ImmutableVector3D { return ImmutableVector3D(x: initialValue, y: initialValue, z: initialValue) } public class func originVector() -> ImmutableVector3D { return equalElementsVector(0) } } In the new ImmutableVector3D class, the sum method returns a new instance of the ImmutableVector3D class—that is, the current class. In this case, the originVector type method returns the results of calling the equalElementsVector type method with 0 as an argument. The equalElementsVector type method receives an initialValue argument for all the elements of the 3D vector, creates an instance of the actual class, and initializes all the elements with the received unique value. The originVector type method demonstrates how we can call another type method within a type method. Note that both the type methods specify the returned type with -> followed by the type name (ImmutableVector3D) after the arguments enclosed in parentheses. The following line shows the declaration for the equalElementsVector type method with the specified return type: public class func equalElementsVector(initialValue: Float) -> ImmutableVector3D { The following lines call the originVector type method to generate an immutable 3D vector named vector0 and the sum method for the generated instance and save the returned instance in the new vector1 variable. The call to the sum method generates a new instance and doesn't mutate the existing object: var vector0 = ImmutableVector3D.originVector() var vector1 = vector0.sum(5, deltaX: 10, deltaY: 15) vector1.printValues() The code doesn't allow the users of the ImmutableVector3D class to change the values of the x, y, and z properties declared with the let keyword. The code doesn't compile if you try to assign a new value to any of these properties after they were initialized. Thus, we can say that the ImmutableVector3D class is 100 percent immutable. Finally, the code calls the printValues method for the returned instance (vector1) to check the values for the three elements on the Playground, as shown in the following screenshot: The immutable version adds an overhead compared with the mutable version because it is necessary to create a new instance of the class as a result of calling the sum method. The previously analyzed mutable version just changed the values for the attributes, and it wasn't necessary to generate a new instance. Obviously, the immutable version has both a memory and performance overhead. However, when we work with concurrent code, it makes sense to pay for the extra overhead to avoid potential issues caused by mutable objects. We just have to make sure we analyze the advantages and tradeoffs in order to decide which is the most convenient way of coding our specific classes. Summary In this article, we learned how to create mutable and immutable classes in Swift. Resources for Article: Further resources on this subject: Exploring Swift[article] The Swift Programming Language[article] Playing with Swift[article]
Read more
  • 0
  • 0
  • 9212

article-image-building-surveys-using-xcode
Packt
19 Jan 2016
14 min read
Save for later

Building Surveys using Xcode

Packt
19 Jan 2016
14 min read
In this article by Dhanushram Balachandran and Edward Cessna author of book Getting Started with ResearchKit, you can find the Softwareitis.xcodeproj project in the Chapter_3/Softwareitis folder of the RKBook GitHub repository (https://github.com/dhanushram/RKBook/tree/master/Chapter_3/Softwareitis). (For more resources related to this topic, see here.) Now that you have learned about the results of tasks from the previous section, we can modify the Softwareitis project to incorporate processing of the task results. In the TableViewController.swift file, let's update the rows data structure to include the reference for processResultsMethod: as shown in the following: //Array of dictionaries. Each dictionary contains [ rowTitle : (didSelectRowMethod, processResultsMethod) ] var rows : [ [String : ( didSelectRowMethod:()->(), processResultsMethod:(ORKTaskResult?)->() )] ] = [] Update the ORKTaskViewControllerDelegate method taskViewController(taskViewController:, didFinishWithReason:, error:) in TableViewController to call processResultsMethod, as shown in the following: func taskViewController(taskViewController: ORKTaskViewController, didFinishWithReason reason: ORKTaskViewControllerFinishReason, error: NSError?) { if let indexPath = tappedIndexPath { //1 let rowDict = rows[indexPath.row] if let tuple = rowDict.values.first { //2 tuple.processResultsMethod(taskViewController.result) } } dismissViewControllerAnimated(true, completion: nil) } Retrieves the dictionary of the tapped row and its associated tuple containing the didSelectRowMethod and processResultsMethod references from rows. Invokes the processResultsMethod with taskViewController.result as the parameter. Now, we are ready to create our first survey. In Survey.swift, under the Surveys folder, you will find two methods defined in the TableViewController extension: showSurvey() and processSurveyResults(). These are the methods that we will be using to create the survey and process the results. Instruction step Instruction step is used to show instruction or introductory content to the user at the beginning or middle of a task. It does not produce any result as its an informational step. We can create an instruction step using the ORKInstructionStep object. It has title and detailText properties to set the appropriate content. It also has the image property to show an image. The ORKCompletionStep is a special type of ORKInstructionStep used to show the completion of a task. The ORKCompletionStep shows an animation to indicate the completion of the task along with title and detailText, similar to ORKInstructionStep. In creating our first Softwareitis survey, let's use the following two steps to show the information: func showSurvey() { //1 let instStep = ORKInstructionStep(identifier: "Instruction Step") instStep.title = "Softwareitis Survey" instStep.detailText = "This survey demonstrates different question types." //2 let completionStep = ORKCompletionStep(identifier: "Completion Step") completionStep.title = "Thank you for taking this survey!" //3 let task = ORKOrderedTask(identifier: "first survey", steps: [instStep, completionStep]) //4 let taskViewController = ORKTaskViewController(task: task, taskRunUUID: nil) taskViewController.delegate = self presentViewController(taskViewController, animated: true, completion: nil) } The explanation of the preceding code is as follows: Creates an ORKInstructionStep object with an identifier "Instruction Step" and sets its title and detailText properties. Creates an ORKCompletionStep object with an identifier "Completion Step" and sets its title property. Creates an ORKOrderedTask object with the instruction and completion step as its parameters. Creates an ORKTaskViewController object with the ordered task that was previously created and presents it to the user. Let's update the processSurveyResults method to process the results of the instruction step and the completion step as shown in the following: func processSurveyResults(taskResult: ORKTaskResult?) { if let taskResultValue = taskResult { //1 print("Task Run UUID : " + taskResultValue.taskRunUUID.UUIDString) print("Survey started at : (taskResultValue.startDate!) Ended at : (taskResultValue.endDate!)") //2 if let instStepResult = taskResultValue.stepResultForStepIdentifier("Instruction Step") { print("Instruction Step started at : (instStepResult.startDate!) Ended at : (instStepResult.endDate!)") } //3 if let compStepResult = taskResultValue.stepResultForStepIdentifier("Completion Step") { print("Completion Step started at : (compStepResult.startDate!) Ended at : (compStepResult.endDate!)") } } } The explanation of the preceding code is given in the following: As mentioned at the beginning, each task run is associated with a UUID. This UUID is available in the taskRunUUID property, which is printed in the first line. The second line prints the start and end date of the task. These are useful user analytics data with regards to how much time the user took to finish the survey. Obtains the ORKStepResult object corresponding to the instruction step using the stepResultForStepIdentifier method of the ORKTaskResult object. Prints the start and end date of the step result, which shows the amount of time for which the instruction step was shown before the user pressed the Get Started or Cancel buttons. Note that, as mentioned earlier, ORKInstructionStep does not produce any results. Therefore, the results property of the ORKStepResult object will be nil. You can use a breakpoint to stop the execution at this line of code and verify it. Obtains the ORKStepResult object corresponding to the completion step. Similar to the instruction step, this prints the start and end date of the step. The preceding code produces screens as shown in the following image: After the Done button is pressed in the completion step, Xcode prints the output that is similar to the following: Task Run UUID : 0A343E5A-A5CD-4E7C-88C6-893E2B10E7F7 Survey started at : 2015-08-11 00:41:03 +0000     Ended at : 2015-08-11 00:41:07 +0000Instruction Step started at : 2015-08-11 00:41:03 +0000   Ended at : 2015-08-11 00:41:05 +0000Completion Step started at : 2015-08-11 00:41:05 +0000   Ended at : 2015-08-11 00:41:07 +0000 Question step Question steps make up the body of a survey. ResearchKit supports question steps with various answer types such as boolean (Yes or No), numeric input, date selection, and so on. Let's first create a question step with the simplest boolean answer type by inserting the following line of code in showSurvey(): let question1 = ORKQuestionStep(identifier: "question 1", title: "Have you ever been diagnosed with Softwareitis?", answer: ORKAnswerFormat.booleanAnswerFormat()) The preceding code creates a ORKQuestionStep object with identifier question 1, title with the question, and an ORKBooleanAnswerFormat object created using the booleanAnswerFormat() class method of ORKAnswerFormat. The answer type for a question is determined by the type of the ORKAnswerFormat object that is passed in the answer parameter. The ORKAnswerFormat has several subclasses such as ORKBooleanAnswerFormat, ORKNumericAnswerFormat, and so on. Here, we are using ORKBooleanAnswerFormat. Don't forget to insert the created question step in the ORKOrderedTask steps parameter by updating the following line: let task = ORKOrderedTask(identifier: "first survey", steps: [instStep, question1, completionStep]) When you run the preceding changes in Xcode and start the survey, you will see the question step with the Yes or No options. We have now successfully added a boolean question step to our survey, as shown in the following image: Now, its time to process the results of this question step. The result is produced in an ORKBooleanQuestionResult object. Insert the following lines of code in processSurveyResults(): //1 if let question1Result = taskResultValue.stepResultForStepIdentifier("question 1")?.results?.first as? ORKBooleanQuestionResult { //2 if question1Result.booleanAnswer != nil { let answerString = question1Result.booleanAnswer!.boolValue ? "Yes" : "No" print("Answer to question 1 is (answerString)") } else { print("question 1 was skipped") } } The explanation of the preceding code is as follows: Obtains the ORKBooleanQuestionResult object by first obtaining the step result using the stepResultForStepIdentifier method, accessing its results property, and finally obtaining the only ORKBooleanQuestionResult object available in the results array. The booleanAnswer property of ORKBooleanQuestionResult contains the user's answer. We will print the answer if booleanAnswer is non-nil. If booleanAnswer is nil, it indicates that the user has skipped answering the question by pressing the Skip this question button. You can disable the skipping-of-a-question step by setting its optional property to false. We can add the numeric and scale type question steps using the following lines of code in showSurvey(): //1 let question2 = ORKQuestionStep(identifier: "question 2", title: "How many apps do you download per week?", answer: ORKAnswerFormat.integerAnswerFormatWithUnit("Apps per week")) //2 let answerFormat3 = ORKNumericAnswerFormat.scaleAnswerFormatWithMaximumValue(10, minimumValue: 0, defaultValue: 5, step: 1, vertical: false, maximumValueDescription: nil, minimumValueDescription: nil) let question3 = ORKQuestionStep(identifier: "question 3", title: "How many apps do you download per week (range)?", answer: answerFormat3) The explanation of the preceding code is as follows: Creates ORKQuestionStep with the ORKNumericAnswerFormat object, created using the integerAnswerFormatWithUnit method with Apps per week as the unit. Feel free to refer to the ORKNumericAnswerFormat documentation for decimal answer format and other validation options that you can use. First creates ORKScaleAnswerFormat with minimum and maximum values and step. Note that the number of step increments required to go from minimumValue to maximumValue cannot exceed 10. For example, maximum value of 100 and minimum value of 0 with a step of 1 is not valid and ResearchKit will raise an exception. The step needs to be at least 10. In the second line, ORKScaleAnswerFormat is fed in the ORKQuestionStep object. The following lines in processSurveyResults() process the results from the number and the scale questions: //1 if let question2Result = taskResultValue.stepResultForStepIdentifier("question 2")?.results?.first as? ORKNumericQuestionResult { if question2Result.numericAnswer != nil { print("Answer to question 2 is (question2Result.numericAnswer!)") } else { print("question 2 was skipped") } } //2 if let question3Result = taskResultValue.stepResultForStepIdentifier("question 3")?.results?.first as? ORKScaleQuestionResult { if question3Result.scaleAnswer != nil { print("Answer to question 3 is (question3Result.scaleAnswer!)") } else { print("question 3 was skipped") } } The explanation of the preceding code is as follows: Question step with ORKNumericAnswerFormat generates the result with the ORKNumericQuestionResult object. The numericAnswer property of ORKNumericQuestionResult contains the answer value if the question is not skipped by the user. The scaleAnswer property of ORKScaleQuestionResult contains the answer for a scale question. As you can see in the following image, the numeric type question generates a free form text field to enter the value, while scale type generates a slider: Let's look at a slightly complicated question type with ORKTextChoiceAnswerFormat. In order to use this answer format, we need to create the ORKTextChoice objects before hand. Each text choice object provides the necessary data to act as a choice in a single choice or multiple choice question. The following lines in showSurvey() create a single choice question with three options: //1 let textChoice1 = ORKTextChoice(text: "Games", detailText: nil, value: 1, exclusive: false) let textChoice2 = ORKTextChoice(text: "Lifestyle", detailText: nil, value: 2, exclusive: false) let textChoice3 = ORKTextChoice(text: "Utility", detailText: nil, value: 3, exclusive: false) //2 let answerFormat4 = ORKNumericAnswerFormat.choiceAnswerFormatWithStyle(ORKChoiceAnswerStyle.SingleChoice, textChoices: [textChoice1, textChoice2, textChoice3]) let question4 = ORKQuestionStep(identifier: "question 4", title: "Which category of apps do you download the most?", answer: answerFormat4) The explanation of the preceding code is as follows: Creates text choice objects with text and value. When a choice is selected, the object in the value property is returned in the corresponding ORKChoiceQuestionResult object. The exclusive property is used in multiple choice questions context. Refer to the documentation for its use. First, creates an ORKChoiceAnswerFormat object with the text choices that were previously created and specifies a single choice type using the ORKChoiceAnswerStyle enum. You can easily change this question to multiple choice question by changing the ORKChoiceAnswerStyle enum to multiple choice. Then, an ORKQuestionStep object is created using the answer format object. Processing the results from a single or multiple choice question is shown in the following. Needless to say, this code goes in the processSurveyResults() method: //1 if let question4Result = taskResultValue.stepResultForStepIdentifier("question 4")?.results?.first as? ORKChoiceQuestionResult { //2 if question4Result.choiceAnswers != nil { print("Answer to question 4 is (question4Result.choiceAnswers!)") } else { print("question 4 was skipped") } } The explanation of the preceding code is as follows: The result for a single or multiple choice question is returned in an ORKChoiceQuestionResult object. The choiceAnswers property holds the array of values for the chosen options. The following image shows the generated choice question UI for the preceding code: There are several other question types, which operate in a very similar manner like the ones we discussed so far. You can find them in the documentations of ORKAnswerFormat and ORKResult classes. The Softwareitis project has implementation of two additional types: date format and time interval format. Using custom tasks, you can create surveys that can skip the display of certain questions based on the answers that the users have provided so far. For example, in a smoking habits survey, if the user chooses "I do not smoke" option, then the ability to not display the "How many cigarettes per day?" question. Form step A form step allows you to combine several related questions in a single scrollable page and reduces the number of the Next button taps for the user. The ORKFormStep object is used to create the form step. The questions in the form are represented using the ORKFormItem objects. The ORKFormItem is similar to ORKQuestionStep, in which it takes the same parameters (title and answer format). Let's create a new survey with a form step by creating a form.swift extension file and adding the form entry to the rows array in TableViewController.swift, as shown in the following: func setupTableViewRows() { rows += [ ["Survey" : (didSelectRowMethod: self.showSurvey, processResultsMethod: self.processSurveyResults)], //1 ["Form" : (didSelectRowMethod: self.showForm, processResultsMethod: self.processFormResults)] ] } The explanation of the preceding code is as follows: The "Form" entry added to the rows array to create a new form survey with the showForm() method to show the form survey and the processFormResults() method to process the results from the form. The following code shows the showForm() method in Form.swift file: func showForm() { //1 let instStep = ORKInstructionStep(identifier: "Instruction Step") instStep.title = "Softwareitis Form Type Survey" instStep.detailText = "This survey demonstrates a form type step." //2 let question1 = ORKFormItem(identifier: "question 1", text: "Have you ever been diagnosed with Softwareitis?", answerFormat: ORKAnswerFormat.booleanAnswerFormat()) let question2 = ORKFormItem(identifier: "question 2", text: "How many apps do you download per week?", answerFormat: ORKAnswerFormat.integerAnswerFormatWithUnit("Apps per week")) //3 let formStep = ORKFormStep(identifier: "form step", title: "Softwareitis Survey", text: nil) formStep.formItems = [question1, question2] //1 let completionStep = ORKCompletionStep(identifier: "Completion Step") completionStep.title = "Thank you for taking this survey!" //4 let task = ORKOrderedTask(identifier: "survey with form", steps: [instStep, formStep, completionStep]) let taskViewController = ORKTaskViewController(task: task, taskRunUUID: nil) taskViewController.delegate = self presentViewController(taskViewController, animated: true, completion: nil) } The explanation of the preceding code is as follows: Creates an instruction and a completion step, similar to the earlier survey. Creates two ORKFormItem objects using the questions from the earlier survey. Notice the similarity with the ORKQuestionStep constructors. Creates ORKFormStep object with an identifier form step and sets the formItems property of the ORKFormStep object with the ORKFormItem objects that are created earlier. Creates an ordered task using the instruction, form, and completion steps and presents it to the user using a new ORKTaskViewController object. The results are processed using the following processFormResults() method: func processFormResults(taskResult: ORKTaskResult?) { if let taskResultValue = taskResult { //1 if let formStepResult = taskResultValue.stepResultForStepIdentifier("form step"), formItemResults = formStepResult.results { //2 for result in formItemResults { //3 switch result { case let booleanResult as ORKBooleanQuestionResult: if booleanResult.booleanAnswer != nil { let answerString = booleanResult.booleanAnswer!.boolValue ? "Yes" : "No" print("Answer to (booleanResult.identifier) is (answerString)") } else { print("(booleanResult.identifier) was skipped") } case let numericResult as ORKNumericQuestionResult: if numericResult.numericAnswer != nil { print("Answer to (numericResult.identifier) is (numericResult.numericAnswer!)") } else { print("(numericResult.identifier) was skipped") } default: break } } } } } The explanation of the preceding code is as follows: Obtains the ORKStepResult object of the form step and unwraps the form item results from the results property. Iterates through each of the formItemResults, each of which will be the result for a question in the form. The switch statement detects the different types of question results and accesses the appropriate property that contains the answer. The following image shows the form step: Considerations for real world surveys Many clinical research studies that are conducted using a pen and paper tend to have well established surveys. When you try to convert these surveys to ResearchKit, they may not convert perfectly. Some questions and answer choices may have to be reworded so that they can fit on a phone screen. You are advised to work closely with the clinical researchers so that the changes in the surveys still produce comparable results with their pen and paper counterparts. Another aspect to consider is to eliminate some of the survey questions if the answers can be found elsewhere in the user's device. For example, age, blood type, and so on, can be obtained from HealthKit if the user has already set them. This will help in improving the user experience of your app. Summary Here we have learned to build surveys using Xcode. Resources for Article: Further resources on this subject: Signing up to be an iOS developer[article] Code Sharing Between iOS and Android[article] Creating a New iOS Social Project[article]
Read more
  • 0
  • 0
  • 5864
article-image-debugging
Packt
14 Jan 2016
11 min read
Save for later

Debugging

Packt
14 Jan 2016
11 min read
In this article by Brett Ohland and Jayant Varma, the authors of Xcode 7 Essentials (Second Edition), we learn about the debugging process, as the Grace Hopper had a remarkable career. She not only became a Rear Admiral in the U.S. Navy but also contributed to the field of computer science in many important ways during her lifetime. She was one of the first programmers on an early computer called Mark I during World War II. She invented the first compiler and was the head of a group that created the FLOW-MATIC language, which would later be extended to create the COBOL programming language. How does this relate to debugging? Well, in 1947, she was leading a team of engineers who were creating the successor of the Mark I computer (called Mark II) when the computer stopped working correctly. The culprit turned out to be a moth that had managed to fly into, and block the operation of, an important relay inside of the computer; she remarked that they had successfully debugged the system and went on to popularize the term. The moth and the log book page that it is attached to are on display in The Smithsonian Museum of American History in Washington D.C. While physical bugs in your systems are an astronomically rare occurrence, software bugs are extremely common. No developer sets out to write a piece of code that doesn't act as expected and crash, but bugs are inevitable. Luckily, Xcode has an assortment of tools and utilities to help you become a great detective and exterminator. In this article, we will cover the following topics: Breakpoints The LLDB console Debugging the view hierarchy Tooltips and a Quick Look (For more resources related to this topic, see here.) Breakpoints The typical development cycle of writing code, compiling, and then running your app on a device or in the simulator doesn't give you much insight into the internal state of the program. Clicking the stop button will, as the name suggests, stop the program and remove it from the memory. If your app crashes, or if you notice that a string is formatted incorrectly or the wrong photo is loaded into a view, you have no idea what code caused the issue. Surely, you could use the print statement in your code to output values on the console, but as your application involves more and more moving parts, this becomes unmanageable. A better option is to create breakpoints. A breakpoint is simply a point in your source code at which the execution of your program will pause and put your IDE into a debugging mode. While in this mode, you can inspect any objects that are in the memory, see a trace of the program's execution flow, and even step the program into or over instructions in your source code. Creating a breakpoint is simple. In the standard editor, there is a gutter that is shown to the immediate left of your code. Most often, there are line numbers in this area, and clicking on a line number will add a blue arrow to that line. That is a breakpoint. If you don't see the line numbers in your gutter, simply open Xcode's settings by going to Xcode | Settings (or pressing the Cmd + , keyboard shortcut) and toggling the line numbers option in the editor section. Clicking on the breakpoint again will dim the arrow and disable the breakpoint. You can remove the breakpoint completely by clicking, dragging, and releasing the arrow indicator well outside of the gutter. A dust ball animation will let you know that it has been removed. You can also delete breakpoints by right-clicking on the arrow indicator and selecting Delete. The Standard Editor showing a breakpoint on line 14 Listing breakpoints You can see a list of all active or inactive breakpoints in your app by opening the breakpoint navigator in the sidebar to the left (Cmd + 7). The list will show the file and line number of each breakpoint. Selecting any of them will quickly take the source editor to that location. Using the + icon at the bottom of the sidebar will let you set many more types of advanced breakpoints, such as the Exception, Symbolic, Open GL Errors, and Test Failure breakpoints. More information about these types can be found on Apple's Developer site at https://developer.apple.com. The debug area When Xcode reaches a breakpoint, its debugging mode will become active. The debug navigator will appear in the sidebar on the left, and if you've printed any information onto the console, the debug area will automatically appear below the editor area: The buttons in the top bar of the debug area are as follows (from left to right): Hide/Show debug area: Toggles the visibility of the debug area Activate/Deactivate breakpoints: This icon activates or deactivates all breakpoints Step Over: Execute the current line or function and pause at the next line Step Into: This executes the current line and jumps to any functions that are called Step Out: This exits the current function and places you at the line of code that called the current function Debug view hierarchy: This shows you a stacked representation of the view hierarchy Location: Since the simulator doesn't have GPS, you can set its location here (Apple HQ, London, and City Bike Ride are some of them) Stack Frame selector: This lets you choose a frame in which the current breakpoint is running The main window of the debug area can be split into two panes: the variables view and the LLDB console. The variables view The variables view shows all the variables and constants that are in the memory and within the current scope of your code. If the instance is a value type, it will show the value, and if it's an object type, you'll see a memory address, as shown in the following screenshot: This view shows all the variables and constants that are in the memory and within the current scope of your code. If the instance is a value type, it will show the value, and if it's an object type, you'll see a memory address. For collection types (arrays and dictionaries), you have the ability to drill down to the contents of the collection by toggling the arrow indicator on the left-hand side of each instance. In the bottom toolbar, there are three sections: Scope selector: This let's you toggle between showing the current scope, showing the global scope, or setting it to auto to select for you Information icons: The Quick Look icon will show quick look information in a popup, while the print information button will print the instance's description on the console Filter area: You can filter the list of values using this standard filter input box The console area The console area is the area where the system will place all system-generated messages as well as any messages that are printed using the print or NSLog statements. These messages will be displayed only while the application is running. While you are in debug mode, the console area becomes an interactive console in the LLDB debugger. This interactive mode lets you print the values of instances in memory, run debugger commands, inspect code, evaluate code, step through, and even skip code. As Xcode has matured over the years, more and more of the advanced information available for you in the console has become accessible in the GUI. Two important and useful commands for use within the console are p and po: po: Prints the description of the object p: Prints the value of an object Depending on the type of variable or constant, p and po may give different information. As an example, let's take a UITableViewCell that was created in our showcase app, now place a breakpoint in the tableView:cellForRowAtIndexPath method in the ExamleTableView class: (lldb) p cell (UITableViewCell) $R0 = 0x7a8f0000 {   UIView = {     UIResponder = {       NSObject = {         isa = 0x7a8f0000       }       _hasAlternateNextResponder = ' '       _hasInputAssistantItem = ' '     }     ... removed 100 lines  (lldb) po cell <UITableViewCell: 0x7a8f0000; frame = (0 0; 320 44); text = 'Helium'; clipsToBounds = YES; autoresize = W; layer = <CALayer: 0x7a6a02c0>> The p has printed out a lot of detail about the object while po has displayed a curated list of information. It's good to know and use each of these commands; each one displays different information. The debug navigator To open the debug navigator, you can click on its icon in the navigator sidebar or use the Cmd + 6 keyboard shortcut. This navigator will show data only while you are in debug mode: The navigator has several groups of information: The gauges area: At a glance, this shows information about how your application is using the CPU, Memory, Disk, Network, and iCloud (only when your app is using it) resources. Clicking on each gauge will show more details in the standard editor area. The processes area: This lists all currently active threads and their processes. This is important information for advanced debugging. The information in the gauges area used to be accessible only if you ran your application in and attached the running process to a separate instruments application. Because of the extra step in running our app in this separate application, Apple started including this information inside of Xcode starting from Xcode 6. This information is invaluable for spotting issues in your application, such as memory leaks, or spotting inefficient code by watching the CPU usage. The preceding screenshot shows the Memory Report screen. Because this is running in the simulator, the amount of RAM available for your application is the amount available on your system. The gauge on the left-hand side shows the current usage as a percentage of the available RAM. The Usage Comparison area shows how much RAM your application is using compared to other processes and the available free space. Finally, the bottom area shows a graph of memory usage over time. Each of these pieces of information is useful for the debugging of your application for crashes and performance. Quick Look There, we were able to see from within the standard editor the contents of variables and constants. While Xcode is in debug mode, we have this very ability. Simply hover the mouse over most instance variables and a Quick Look popup will appear to show you a graphical representation, like this: Quick Look knows how to handle built-in classes, such as CGRect or UIImage, but what about custom classes that you create? Let's say that you create a class representation of an Employee object. What information would be the best way to visualize an instance? You could show the employee's photo, their name, their employee number, and so on. Since the system can't judge what information is important, it will rely on the developer to decide. The debugQuickLookObject() method can be added to any class, and any object or value that is returned will show up within the Quick Look popup: func debugQuickLookObject() -> AnyObject {     return "This is the custom preview text" } Suppose we were to add that code to the ViewController class and put a breakpoint on the super.viewDidLoad() line: import UIKit class ViewController: UIViewController {       override func viewDidLoad() {         super.viewDidLoad()         // Do any additional setup after loading the view, typically from a nib.     }       override func didReceiveMemoryWarning() {         super.didReceiveMemoryWarning()         // Dispose of any resources that can be recreated.     }       func debugQuickLookObject() -> AnyObject {         return "I am a quick look value"     }   } Now, in the variables list in the debug area, you can click on the Quick Look icon, and the following screen will appear: Summary Debugging is an art as well as a science. Because of this, it easily can—and does—take entire books to cover the subject. The best way to learn techniques and tools is by experimenting on your own code. Resources for Article:   Further resources on this subject: Introduction to GameMaker: Studio [article] Exploring Swift [article] Using Protocols and Protocol Extensions [article]
Read more
  • 0
  • 0
  • 2570

article-image-creating-adaptive-application-layout
Packt
14 Jan 2016
17 min read
Save for later

Creating an Adaptive Application Layout

Packt
14 Jan 2016
17 min read
In this article by Jim Wilson, the author of the book, Creating Dynamic UI with Android Fragments - Second Edition, we will see how to create an adaptive application layout. (For more resources related to this topic, see here.) In our application, we'll leave the wide-display aspect of the program alone because static layout management is working fine there. We work on the portrait-oriented handset aspect of the application. For these devices, we'll update the application's main activity to dynamically switch between displaying the fragment containing the list of books and the fragment displaying the selected book's description. Updating the layout to support dynamic fragments Before we write any code to dynamically manage the fragments within our application, we first need to modify the activity layout resource for portrait-oriented handset devices. This resource is contained in the activity_main.xml layout resource file that is not followed by (land) or (600dp). The layout resource currently appears as shown here: <LinearLayout android_orientation="vertical" android_layout_width="match_parent" android_layout_height="match_parent" > <!-- List of Book Titles --> <fragment android_layout_width="match_parent" android_layout_height="0dp" android_layout_weight="1" android_name="com.jwhh.fragments.BookListFragment2" android_id="@+id/fragmentTitles" tools_layout="@layout/fragment_book_list"/> </LinearLayout> We need to make two changes to the layout resource. The first is to add an id attribute to the LinearLayout view group so that we can easily locate it in code. The other change is to completely remove the fragment element. The updated layout resource now contains only the LinearLayout view group, which includes an id attribute value of @+id/layoutRoot. The layout resource now appears as shown here: <LinearLayout android_id="@+id/layoutRoot" android_orientation="vertical" android_layout_width="match_parent" android_layout_height="match_parent" > </LinearLayout> We still want our application to initially display the book list fragment, so removing the fragment element may seem like a strange change, but doing so is essential as we move our application to dynamically manage the fragments. We will eventually need to remove the book list fragment to replace it with the book description fragment. If we were to leave the book list fragment in the layout resource, our attempt to dynamically remove it later would silently fail. Only dynamically added fragments can be dynamically removed. Attempting to dynamically remove a fragment that was statically added with the fragment element in a layout resource will silently fail. Adapting to device differences When our application is running on a portrait-oriented handset device, the activity needs to programmatically load the fragment containing the book list. This is the same Fragment class, BookListFragment2, we were previously loading with the fragment element in the activity_main.xml layout resource file. Before we load the book list fragment, we first need to determine whether we're running on a device that requires dynamic fragment management. Remember that, for the wide-display devices, we're going to leave the static fragment management in place. There'll be a couple of places in our code where we'll need to take different logic paths depending on which layout we're using. So we'll need to add a boolean class-level field to the MainActivity class in which we can store whether we're using dynamic or static fragment management: boolean mIsDynamic; We can interrogate the device for its specific characteristics such as screen size and orientation. However, remember that much of our previous work was to configure our application to take the advantage of the Android resource system to automatically load the appropriate layout resources based on the device characteristics. Rather than repeating those characteristics checks in code, we can instead simply include the code to determine which layout resource was loaded. The layout resource for wide-display devices we created earlier, activity_main_wide.xml, statically loads both the book list fragment and the book description fragment. We can include in our activity's onCreate method code to determine whether the loaded layout resource includes one of those fragments as shown here: public class MainActivity extends Activity implements BookListFragment.OnSelectedBookChangeListener { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_dynamic); // Get the book description fragment FragmentManager fm = getFragmentManager(); Fragment bookDescFragment = fm.findFragmentById(R.id.fragmentDescription); // If not found than we're doing dynamic mgmt mIsDynamic = bookDescFragment == null || !bookDescFragment.isInLayout(); } // Other members elided for clarity } When the call to the setContentView method returns, we know that the appropriate layout resource for the current device has been loaded. We then use the FragmentManager instance to search for the fragment with an id value of R.id.fragmentDescription that is included in the layout resource for wide-display devices, but not the layout resource for portrait-oriented handsets. A return value of null indicates that the fragment was not loaded and we are, therefore, on a device that requires us to dynamically manage the fragments. In addition to the test for null, we also include the call to the isInLayout method to protect against one special case scenario. In the scenario where the device is in a landscape layout and then rotated to portrait, a cached instance to the fragment identified by R.id.fragmentDescription may still exist even though in the current orientation, the activity is not using the fragment. By calling the isInLayout method, we're able to determine whether the returned reference is part of the currently loaded layout. With this, our test to set the mIsDynamic member variable effectively says that we'll set mIsDynamic to true when the R.id.fragmentDescription fragment is not found (equals null), or it's found but is not a part of the currently loaded layout (!bookDescFragment.isInLayout). Dynamically loading a fragment at startup Now that we're able to determine whether or not dynamically loading the book list fragment is necessary, we add the code to do so to our onCreate method as shown here: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_dynamic); // Get the book description fragment FragmentManager fm = getFragmentManager(); Fragment bookDescFragment = fm.findFragmentById(R.id.fragmentDescription); // If not found than we're doing dynamic mgmt mIsDynamic = bookDescFragment == null || !bookDescFragment.isInLayout(); // Load the list fragment if necessary if (mIsDynamic) { // Begin transaction FragmentTransaction ft = fm.beginTransaction(); // Create the Fragment and add BookListFragment2 listFragment = new BookListFragment2(); ft.add(R.id.layoutRoot, listFragment, "bookList"); // Commit the changes ft.commit(); } } Following the check to determine whether we're on a device that requires dynamic fragment management, we include FragmentTransaction to add an instance of the BookListFragment2 class to the activity as a child of the LinearLayout view group identified by the id value R.id.layoutRoot. This code capitalizes on the changes we made to the activity_main.xml resource file by removing the fragment element and including an id value on the LinearLayout view group. Now that we're dynamically loading the book list, we're ready to get rid of that other activity. Transitioning between fragments As you'll recall, whenever the user selects a book title within the BookListFragment2 class, the fragment notifies the main activity by calling the MainActivity.onSelectedBookChanged method passing the index of the selected book. The onSelectedBookChanged method currently appears as follows: public void onSelectedBookChanged(int bookIndex) { FragmentManager fm = getFragmentManager(); // Get the book description fragment BookDescFragment bookDescFragment = (BookDescFragment) fm.findFragmentById(R.id.fragmentDescription); // Check validity of fragment reference if(bookDescFragment == null || !bookDescFragment.isVisible()){ // Use activity to display description Intent intent = new Intent(this, BookDescActivity.class); intent.putExtra("bookIndex", bookIndex); startActivity(intent); } else { // Use contained fragment to display description bookDescFragment.setBook(bookIndex); } } In the current implementation, we use a technique similar to what we did in the onCreate method to determine which layout is loaded; we try to find the book description fragment within the currently loaded layout. If we find it, we know the current layout includes the fragment, so we go ahead and set the book description directly on the fragment. If we don't find it, we call the startActivity method to display the activity that contains the book description fragment. Starting a separate activity to handle the interaction with the BookListFragment2 class unnecessarily adds complexity to our program. Doing so requires that we pass data from one activity to another, which can sometimes be complex, especially if there are a large number of values or some of those values are object types that require additional coding to be passed in an Intent instance. More importantly, using a separate activity to manage the interaction with the BookListFragment2 class results in redundant work due to the fact that we already have all the code necessary to interact with the BookListFragment2 class in the MainActivity class. We'd prefer to handle the interaction with the BookListFragment2 class consistently in all cases. Eliminating redundant handling To eliminate this redundant handling, we start by stripping any code in the current implementation that deals with starting an activity. We can also avoid repeating the check for the book description fragment because we performed that check earlier in the onCreate method. Instead, we can now check the mIsDynamic class-level field to determine the proper handling. With that in mind, now we can initially modify the onSelectedBookChanged method to look like the following code: public void onSelectedBookChanged(int bookIndex) { BookDescFragment bookDescFragment; FragmentManager fm = getFragmentManager(); // Check validity of fragment reference if(mIsDynamic) { // Handle dynamic switch to description fragment } else { // Use the already visible description fragment bookDescFragment = (BookDescFragment) fm.findFragmentById(R.id.fragmentDescription); bookDescFragment.setBook(bookIndex); } } We now check the mIsDynamic member field to determine the appropriate code path. We still have some work to do if it turns out to be true, but in the case of it being false, we can simply get a reference to the book description fragment that we know is contained within the current layout and set the book index on it much like we were doing before. Creating the fragment on the fly In the case of the mIsDynamic field being true, we can display the book description fragment by simply replacing the book list fragment we added in the onCreate method with the book description fragment using the code shown here: FragmentTransaction ft = fm.beginTransaction(); bookDescFragment = new BookDescFragment(); ft.replace(R.id.layoutRoot, bookDescFragment, "bookDescription"); ft.addToBackStack(null); ft.setCustomAnimations( android.R.animator.fade_in, android.R.animator.fade_out); ft.commit(); Within FragmentTransaction, we create an instance of the BookDescFragment class and call the replace method passing the ID of the same view group that contains the BookListFragment2 instance that we added in the onCreate method. We include a call to the addToBackStack method so that the back button functions correctly, allowing the user to tap the back button to return to the book list. The code includes a call to the FragmentTransaction class' setCustomAnimations method that creates a fade effect when the user switches from one fragment to another. Managing asynchronous creation We have one final challenge that is to set the book index on the dynamically added book description fragment. Our initial thought might be to simply call the BookDescFragment class' setBook method after we create the BookDescFragment instance, but let's first take a look at the current implementation of the setBook method. The method currently appears as follows: public void setBook(int bookIndex) { // Lookup the book description String bookDescription = mBookDescriptions[bookIndex]; // Display it mBookDescriptionTextView.setText(bookDescription); } The last line of the method attempts to set the value of mBookDescriptionTextView within the fragment, which is a problem. Remember that the work we do within a FragmentTransaction class is not immediately applied to the user interface. Instead, as we discussed earlier in this chapter, in the deferred execution of transaction changes section, the work within the transaction is performed sometime after the completion of the call to the commit method. Therefore, the BookDescFragment instance's onCreate and onCreateView methods have not yet been called. As a result, any views associated with the BookDescFragment instance have not yet been created. An attempt to call the setText method on the BookDescriptionTextView instance will result in a null reference exception. One possible solution is to modify the setBook method to be aware of the current state of the fragment. In this scenario, the setBook method checks whether the BookDescFragment instance has been fully created. If not, it will store the book index value in the class-level field and later automatically set the BookDescriptionTextView value as part of the creation process. Although there may be some scenarios that warrant such a complicated solution, fragments give us an easier one. The Fragment base class includes a method called setArguments. With the setArguments method, we can attach data values, otherwise known as arguments, to the fragment that can then be accessed later in the fragment lifecycle using the getArguments method. Much like we do when associating extras with an Intent instance, a good practice is to define constants on the target class to name the argument values. It is also a good programming practice to provide a constant for an argument default value in the case of non-nullable types such as integers as shown here: public class BookDescFragment extends Fragment { // Book index argument name public static final String BOOK_INDEX = "book index"; // Book index default value private static final int BOOK_INDEX_NOT_SET = -1; // Other members elided for clarity } If you used Android Studio to generate the BookDescFragment class, you'll find that the ARG_PARAM1 and ARG_PARAM2 constants are included in the class. Android Studio includes these constants to provide examples of how to pass values to fragments just as we're discussing now. Since we're adding our own constant declarations, you can delete the ARG_PARAM1 and ARG_PARAM2 constants from the BookDescFragment class and also the lines in the generated BookDescFragment.onCreate and BookDescFragment.newInstance methods that reference them. We'll use the BOOK_INDEX constant to get and set the book index value and the BOOK_INDEX_NOT_SET constant to indicate whether the book index argument has been set. To simplify the process of creating the BookDescFragment instance and passing it the book index value, we'll add a static factory method named newInstance to the BookDescFragment class that appears as follows: public static BookDescFragment newInstance(int bookIndex) { BookDescFragment fragment = new BookDescFragment(); Bundle args = new Bundle(); args.putInt(BOOK_INDEX, bookIndex); fragment.setArguments(args); return fragment; } The newInstance methods start by creating an instance of the BookDescFragment class. It then creates an instance of the Bundle class, stores the book index in the Bundle instance, and then uses the setArguments method to attach it to the BookDescFragment instance. Finally, the newInstance method returns the BookDescFragment instance. We'll use this method shortly within the MainActivity class to create our BookDescFragment instance. If you used Android Studio to generate the BookDescFragment class, you'll find that most of the newInstance method is already in place. The only change you'll have to make is replace the two lines that referenced the ARG_PARAM1 and ARG_PARAM2 constants you deleted with the call to the args.putInt method shown in the preceding code. We can now update the BookDescFragment class' onCreateView method to look for arguments that might be attached to the fragment. Before we make any changes to the onCreateView method, let's look at the current implementation that appears as follows: public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View viewHierarchy = inflater.inflate( R.layout.fragment_book_desc, container, false); // Load array of book descriptions mBookDescriptions = getResources().getStringArray(R.array.bookDescriptions); // Get reference to book description text view mBookDescriptionTextView = (TextView) viewHierarchy.findViewById(R.id.bookDescription); return viewHierarchy; } As the onCreateView method is currently implemented, it simply inflates the layout resource, loads the array containing the book descriptions, and caches a reference to the TextView instance where the book description is loaded. We can now update the method to look for and use a book index that might be attached as an argument. The updated method appears as follows: public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View viewHierarchy = inflater.inflate( R.layout.fragment_book_desc, container, false); // Load array of book descriptions mBookDescriptions = getResources().getStringArray(R.array.bookDescriptions); // Get reference to book description text view mBookDescriptionTextView = (TextView) viewHierarchy.findViewById(R.id.bookDescription); // Retrieve the book index if attached Bundle args = getArguments(); int bookIndex = args != null ? args.getInt(BOOK_INDEX, BOOK_INDEX_NOT_SET) : BOOK_INDEX_NOT_SET; // If we find the book index, use it if (bookIndex != BOOK_INDEX_NOT_SET) setBook(bookIndex); return viewHierarchy; } Just before we return the fragment's view hierarchy, we call the getArguments method to retrieve any arguments that might be attached. The arguments are returned as an instance of the Bundle class. If the Bundle instance is non-null, we call the Bundle class' getInt method to retrieve the book index and assign it to the bookIndex local variable. The second parameter of the getInt method, BOOK_INDEX_NOT_SET, is returned if the fragment happens to have arguments attached that do not include the book index. Although this should not normally be the case, being prepared for any such an unexpected circumstance is a good idea. Finally, we check the value of the bookIndex variable. If it contains a book index, we call the fragment's setBook method to display it. Putting it all together With the BookDescFragment class now including support for attaching the book index as an argument, we're ready to fully implement the main activity's onSelectedBookChanged method to include switching to the BookDescFragment instance and attaching the book index as an argument. The method now appears as follows: public void onSelectedBookChanged(int bookIndex) { BookDescFragment bookDescFragment; FragmentManager fm = getFragmentManager(); // Check validity of fragment reference if(mIsDynamic){ // Handle dynamic switch to description fragment FragmentTransaction ft = fm.beginTransaction(); // Create the fragment and pass the book index bookDescFragment = BookDescFragment.newInstance(bookIndex); // Replace the book list with the description ft.replace(R.id.layoutRoot, bookDescFragment, "bookDescription"); ft.addToBackStack(null); ft.setCustomAnimations( android.R.animator.fade_in, android.R.animator.fade_out); ft.commit(); } else { // Use the already visible description fragment bookDescFragment = (BookDescFragment) fm.findFragmentById(R.id.fragmentDescription); bookDescFragment.setBook(bookIndex); } } Just as before, we start with the check to see whether we're doing dynamic fragment management. Once we determine that we are, we start the FragmentTransaction instance and create the BookDescFragment instance. We then create a new Bundle instance, store the book index into it, and then attach the Bundle instance to the BookDescFragment instance with the setArguments method. Finally, we put the BookDescFragment instance into place as the current fragment, take care of the back stack, enable animation, and complete the transaction. Everything is now complete. When the user selects a book title from the list, the onSelectedBookChanged method gets called. The onSelectedBookChanged method then creates and displays the BookDescFragment instance with the appropriate book index attached as an argument. When the BookDescFragment instance is ultimately created, its onCreateView method will then retrieve the book index from the arguments and display the appropriate description. Summary In this article, we saw that using the FragmentTransaction class, we're able to dynamically switch between individual fragments within an activity, eliminating the need to create a separate activity class for each screen in our application. This helps to prevent the proliferation of unnecessary activity classes, better organize our applications, and avoid the associated increase in complexity. Resources for Article: Further resources on this subject: UI elements and their implementation[article] Creating Dynamic UI with Android Fragments[article] Android Fragmentation Management[article]
Read more
  • 0
  • 0
  • 1309

article-image-first-look-ionic
Packt
13 Jan 2016
9 min read
Save for later

First Look at Ionic

Packt
13 Jan 2016
9 min read
In this article, Sani Yusuf the author of the book Ionic Framework By Example, explains how Ionic framework lets you build Hybrid mobile applications with web technologies such as HTML5, CSS, and JavaScript. But that is not where it stops. Ionic provides you with components that you use to build native-like features for your mobile applications. Think of Ionic as the SDK for making your Hybrid mobile application. Most of the feature you have on native apps such as Modals, Gestures, and POP-UPs etc are all provided to you by Ionic and can be easily extended for new features or customized to suit your needs. Ionic itself does not grant you the ability to communicate with device features such as GPS and Camera, instead it works side by side with Cordova to achieve this. Another great feature of Ionic is how loosely coupled all its components are. You can decide to use only some of Ionic on an already existing hybrid application if you wish to do so. The Ionic framework is built with AngularJS, which is arguably the most well tested and widely used JavaScript framework out there. This feature is particularly powerful as it gives you all the goodness of angular as a part of any Ionic app you develop. In the past, architecting hybrid application proved to be difficult, but with angular, we can create our mobile application using the Single Page Application (SPA) technique. Angular also makes it really easy to organize your application for development and working across teams whiles providing you the possibility of easily adding custom features or libraries. (For more resources related to this topic, see here.) Features of Ionic Ionic provides you with a lot of cool neat features and tricks that help you create beautiful and well-functional hybrid apps in no time. The features of Ionic come under three categories: CSS features JavaScript features Ionic CLI CSS features To start off with, Ionic comes in stock with a great CSS library that provides you with some boilerplate styles. This Ionic CSS styles are generated with SASS, a CSS pre-processor for more advanced CSS style manipulation. Some of the cool CSS features that come built-in with Ionic include: Buttons Cards Header and Footers Lists Forms Elements Grid System All these features and many more come already provided for you and are easily customizable. They also have the same look and feel that native equivalents have, so you will not have to do any editing to make them look like native components. The JavaScript features The JavaScript features are at the heart of the Ionic framework and are essential for building Ionic apps. They also consist of other features that let you do things from under hood like customize your application or even provide you with helper functions that you can use to make developing your app more pleasant. A lot of these JavaScript features actually exist as HTML custom elements that make it easy to declaratively use these features. Some of these features include: Modal Slide-Box Action Sheet Side Menu Tabs Complex Lists Collection Repeat All the JavaScript features of Ionic are built with Angular, and most can be easily plugged in as angular directives. Each of them also perform different actions that help you achieve specific functions and are all documented in the Ionic website. The Ionic CLI This is the final part that makes up the three major arms of the Ionic framework. The Ionic CLI is a very important tool that lets you use the issue Ionic commands via the command line/terminal. It is also with the Ionic CLI that we get access to some Ionic features that make our app development process more streamlined. It is arguably most important part of Ionic and it is also the feature you will use to do most actions. The features of the Ionic CLI include: Creating Ionic projects Issuing Cordova commands Developing and testing Ionic splash/Icon generator Ionic labs SASS Uploading the app to Ionic view Accessing Ionic.IO tools The Ionic CLI is a very powerful tool, and for the most part it is the tool we will be using throughout this book to perform specific actions. This is why the first thing we are going to do is to set up the Ionic CLI. Setting up Ionic The following steps will give a brief of how to setup Ionic: Install Node JS: To set up Ionic, the first thing you will need to do is to install Node JS on your computer so that you can have access to Node Package Manager (NPM). If you already have node installed on your computer, you can skip this step and got to step 2. Go to www.nodejs.org and click on the Install button. That should download the latest version of Node JS on your computer. Don't worry if you are on a Mac, PC, or Linux, the correct one for your operating system will be automatically downloaded. After the download is finished, install the downloaded software on your computer. You may need to restart your computer if you are running windows. Open up the terminal if you are on Mac/Linux or the Windows command line if you are on a Windows machine. Type the following command node –v and press Enter. You should see the version number of your current installation of Node JS. If you do not see a version number, this might mean that you have not correctly installed Node JS and should try running step 1 again. Install Ionic CLI: The next step is to use NPM to install the Ionic CLI. Open a new Terminal (OSX and Linux) or command line (Windows) window and run the npm install Ionic –g command. If you are on Linux/OSX, you might need to run sudo install Ionic –g. This command will aim to install Ionic globally. After this has finished running, run the Ionic –v command on your Terminal/command line and press Enter. You should have seen a version number of your Ionic CLI. This means that you have Ionic installed correctly and are good to go. If you do not see a version number, then you have not installed Ionic correctly on your machine and should perform step 2 again. The Ionic workflow When you create a new Ionic project, there are a couple of folders and files that come in stock. You directory should look similar to the following screenshot: The structure you see is pretty much the same as in every Cordova project with the exception of a few files and folders. For example, there is an scss folder. This contains a file that lets us customize the look and feel of our application. You will also note that in your www/lib folder, there is a folder called ionic, which contains all the required files to run Ionic. There is a CSS, fonts, JS, and SCSS folder: CSS: This folder contains all the default CSS that come with an Ionic app. Fonts: Ionic comes with its own font and Icon library called Ionicons. This Ionicons library contains hundreds of icons, which are all available for use in your app. JS: This contains all the code for the core Ionic library. Since Ionic is built with angular, there is a version of Angular here with a bunch of other files that make up the ionic framework. SCSS: This is a folder that contains SASS files used to build the beautiful Ionic framework CSS styles. Everything here can be overwritten easily. If you take a look at the root folder, you will see a lot of other files that are generated for you as part of the Ionic workflow. These files are not overly important now, but let's take a look at the more important ones: Bower.json: This is the file that contains some of the dependencies gotten from the bower package manager. The bower dependencies are resolved in the lib folder by as specified in the bowerrc file. This is a great place to specify other third party dependencies that your project might need. Config.xml: This is the standard config file that comes along with any Phonegap/Cordova project. This is where you request permissions for device features and also specify universal and platform-specific configurations for you app. Gulpfile: Ionic uses the gulp build tool, and this file contains some code that is provided by Ionic that enables you do some amazing things. Ionic.project: This is a file specific for Ionic services. It is the file used by the Ionic CLI and the Ionic.IO services as a place to specify some of your Ionic specific configuration. Package.json: This is a file used by node to specify some node dependencies. When you create a project with the Ionic CLI, Ionic uses both the Node and Bowe Package manager to resolve some of your dependencies. If you require a node module when you are developing ionic apps, you can specify these dependencies here. These files are some of the more important files that come stock with a project created with the Ionic CLI. At the moment, you do not need to worry too much about them but it's always good to know that they exist and have an idea about what they actually represent. Summary In this article, we discussed exactly what Ionic means and what problems it aims to solve. We also got to discuss the CSS, JS, and Ionic CLI features of the Ionic framework lightly. Resources for Article: Further resources on this subject: Ionic JS Components [article] Creating Instagram Clone Layout using Ionic framework [article] A Virtual Machine for a Virtual World [article]
Read more
  • 0
  • 0
  • 1503
article-image-project-structure
Packt
08 Jan 2016
14 min read
Save for later

The Project Structure

Packt
08 Jan 2016
14 min read
In this article written by Nathanael Anderson, author of the book Getting Started with NativeScript, we will see how to navigate through your new project and its full structure. We will explain each of the files that are automatically created and where you create your own files. Then, we will proceed to gain a deeper understanding of some of the basic components of your application, and we will finally see how to change screens. In this article, we will cover the following topics: An overview of the project directory The root directory The application components (For more resources related to this topic, see here.) Project directory overview By running the nativescript create crossCommunicator command, the command creates a nice structure of files and folders for us to explore. First, we will do a high level overview of the different folders and their purposes and touch on the important files in those folders. Then, we will finish the overview by going into depth about the App directory, which is where you will spend pretty much your entire time in developing an application. To give you a good visual overview, here is what the project hierarchy structure looks like: The root directory In your Root folder, you will see only a couple of directories. The package.json file will look something like this: {   "nativescript": {     "id": "org.nativescript.crossCommunicator",     "tns-android": {       "version": "1.5.0"     },     "tns-ios": {       "version": "1.5.0"     },   },   "dependencies": {     "tns-core-modules": "1.5.0"   } } This is the NativeScript master project configuration file for your entire application. It basically outlines the basic information and all platform requirements of the project. It will also be modified by the nativescript tool when you add and remove any plugins or platforms. So, in the preceding package.json file, you can see that I have installed the Android (tns-android) and iOS (tns-ios) platforms, using the nativscript platform add command, and they are both currently at version 1.5.0. The tns-core-modules dependency was added by the nativescript command when we created the project and it is the core modules. Changing the app ID Now, if you want this to be your company's name instead of the default ID of org.nativescript.yourProjectName, there are two ways to set the app ID. The first way is to set it up when you create the project; executing a nativescript create myProjName --appid com.myCompany.myProjName command will automatically set the ID value. If you forget to run the create command with a --appid option; you can change it here. However, any time you change the option here, you will also have to remove all the installed platforms and then re-add the platforms you are using. This must be done as when each platform is added because it uses this configuration id while building all the platform folders and all of the needed platform files. The package.json file This file contains basic information about the current template that is installed. When you create a new application via the nativescript create command, by default, it copies everything from a template project called tns-template-hello-world. In the future, NativeScript will allow you to choose the template, but currently this is the only template that is available and working. This template contains the folders we discussed earlier and all the files that we will discuss further. The package.json file is from this template, and it basically tells you about the template and its specific version that is installed. Le's take a look at the following code snippet: {   "name": "tns-template-hello-world",   "main": "app.js",   "version": "1.5.0", ... more json documentation fields... } Feel free to modify the package.json file so that it matches your project's name and details. This file currently does not currently serve much purpose beyond template documentation and the link to the main application file. License The License file that is present in the the App folder is the license that the tns-template-hello-world is under. In your case, your app will probably be distributed under a different license. You can either update this file to match your application's license or delete it. App.js Awesome! We have finally made it to the first of the JavaScript files that make up the code that we will change to make this our application. This file is the bootstrap file of the entire application, and this is where the fun begins. In the preceding package.json file, you can see that the package.json file references this file (app.js) under the main key. This key in the package.json file is what NativeScript uses to make this file the entry point for the entire application. Looking at this file, we can see that it currently has four simple lines of code: var application = require("application"); application.mainModule = "main-page"; application.cssFile = "./app.css"; application.start(); The file seems simple enough, so let's work through the code as we see it. The first line loads the NativeScript common application component class, and the application component wraps the initialization and life cycle of the entire application. The require() function is the what we use to reference another file in your project. It will look in your current directory by default and then it will use some additional logic to look into a couple places in the tns_core_modules folder to check whether it can find the name as a common component. Now that we have the application component loaded, the next lines are used to configure what the application class does when your program starts and runs. The second line tells which one of the files is the main page. The third line tells the application which CSS file is the main CSS file for the entire application. And finally, we tell the application component to actually start. Now, in a sense, the application has actually started running, we are already running our JavaScript code. This start() function actually starts the code that manages the application life cycle and the application events, loads and applies your main CSS file, and finally loads your main page files. If you want to add any additional code to this file, you will need to put it before the application.start() command. On some platforms, nothing below the application.start() command will be run in the app.js file. The main-page.js file The JavaScript portion of the page is probably where you will spend the majority of your time developing, as it contains all of the logic of your page. To create a page, you typically have a JavaScript file as you can do everything in JavaScript, and this is where all your logic for the page resides. In our application, the main page currently has only six lines of code: var vmModule = require("./main-view-model"); function pageLoaded(args) {   var page = args.object;   page.bindingContext = vmModule.mainViewModel; } exports.pageLoaded = pageLoaded; The first line loads the main-view-model.js file. If you haven't guessed yet, in our new application, this is used as the model file for this page. We will check out the optional model file in a few minutes after we are done exploring the rest of the main-page files. An app page does not have to have a model, they are totally optional. Furthermore, you can actually combine your model JavaScript into the page's JavaScript file. Some people find it easier to keep their model separate, so when Telerik designed this example, they built this application using the MVVM pattern, which uses a separate view model file. For more information on MVVM, you can take a look at the Wikipedia entry at https://en.wikipedia.org/wiki/Model_View_ViewModel. This file also has a function called pageLoaded, which is what sets the model object as the model for this page. The third line assigns the page variable to the page component object that is passed as part of the event handler. The fourth line assigns the model to the current page's bindingContext attribute. Then, we export the pageLoaded function as a function called pageLoaded. Using exports and module.exports is the way in which we publish something to other files that use require() to load it. Each file is its own independent blackbox, nothing that is not exported can be seen by any of the other files. Using exports, you can create the interface of your code to the rest of the world. This is part of the CommonJS standard, and you can read more about it at the NodeJS site. The main-page.xml file The final file of our application folder is also named main-page; it is the page layout file. As you can see, the main-page.xml layout consists of seven simple lines of XML code, which actually does quite a lot, as you can see: <Page loaded="pageLoaded">   <StackLayout>     <Label text="Tap the button" cssClass="title"/>     <Button text="TAP" tap="{{ tapAction }}" />     <Label text="{{ message }}" cssClass="message"     textWrap="true"/>   </StackLayout> </Page> Each of the XML layout files are actually a simplified way to load your visual components that you want on your page. In this case, it is what made your app look like this: The main-view-model.js file The final file in our tour of the App folder is the model file. This file has about 30 lines of code. By looking at the first couple of lines, you might have figured out that this file was transpiled from TypeScript. Since this file actually has a lot of boilerplate and unneeded code from the TypeScript conversion, we will rewrite the code in plain JavaScript to help you easily understand what each of the parts are used for. This rewrite will be as close to what as I can make it. So without further ado, here is the original transpiled code to compare our new code with: var observable = require("data/observable"); var HelloWorldModel = (function (_super) {   __extends(HelloWorldModel, _super);   function HelloWorldModel() {     _super.call(this);     this.counter = 42;     this.set("message", this.counter + " taps left");   }   HelloWorldModel.prototype.tapAction = function () {     this.counter--;     if (this.counter <= 0) {       this.set("message", "Hoorraaay! You unlocked the       NativeScript clicker achievement!");     }     else {       this.set("message", this.counter + " taps left");     }   };   return HelloWorldModel; })(observable.Observable); exports.HelloWorldModel = HelloWorldModel; exports.mainViewModel = new HelloWorldModel(); The Rewrite of the main-view-model.js file The rewrite of the main-view-model.js file is very straightforward. The first thing we need for a working model to also require the Observable class is the primary class that handles data binding events in NativeScript. We then create a new instance of the Observable class named mainViewModel. Next, we need to assign the two default values to the mainViewModel instance. Then, we create the same tapAction() function, which is the code that is executed each time when the user taps on the button. Finally, we export the mainViewModel model we created so that it is available to any other files that require this file. This is what the new JavaScript version looks like: // Require the Observable class and create a new Model from it var Observable = require("data/observable").Observable; var mainViewModel = new Observable(); // Setup our default values mainViewModel.counter = 42; mainViewModel.set("message", mainViewModel.counter + " taps left"); // Setup the function that runs when a tap is detected. mainViewModel.tapAction = function() {   this.counter--;   if (this.counter <= 0) {     this.set("message", "Hoorraaay! You unlocked the NativeScript     clicker achievement!");   } else {     this.set("message", this.counter + " taps left");   } }; // Export our already instantiated model class as the variable name that the main-page.js is expecting on line 4. exports.mainViewModel = mainViewModel; The set() command is the only thing that is not totally self-explanatory or explained in this code. What is probably fairly obvious is that this command sets the variable specified to the value specified. However, what is not obvious is when a value is set on an instance of the Observable class, it will automatically send a change event to anyone who has asked to be notified of any changes to that specific variable. If you recall, in the main-page.xml file, the: <Label text="{{ message }}" ….> line will automatically register the label component as a listener for all change events on the message variable when the layout system creates the label. Now, every time the message variable is changed, the text on this label changes. The application component If you recall, earlier in the article, we discussed the app.js file. It basically contains only the code to set up the properties of your application, and then finally, it starts the application component. So, you probably have guessed that this is the primary component for your entire application life cycle. A part of the features that this component provides us is access to all the application-wide events. Frequently in an app, you will want to know when your app is no longer the foreground application or when it finally returns to being the foreground application. To get this information, you can attach  the code to two of the events that it provides like this: application.on("suspend", function(event) {   console.log("Hey, I was suspended – I thought I was your   favorite app!"); }); application.on("resume", function(event) {   console.log("Awesome, we are back!"); }); Some of the other events that you can watch from the application component are launch, exit, lowMemory and uncaughtError. These events allow you to handle different application wide issues that your application might need to know about. Creating settings.js In our application, we will need a settings page; so, we will create the framework for our application's setting page now. We will just get our feet a little wet and explore how to build it purely in JavaScript. As you can see, the following code is fairly straightforward. First, we require all the components that we will be using: Frame, Page, StackLayout, Button, and finally, the Label component. Then, we have to export a createPage function, which is what NativeScript will be running to generate the page if you do not have an XML layout file to go along with the page's JavaScript file. At the beginning of our createPage function, we create each of the four components that we will need. Then, we assign some values and properties to make them have some sort of visual capability that we will be able to see. Next, we create the parent-child relationships and add our label and button to the Layout component, and then we assign that layout to the Page component. Finally, we return the page component: // Add our Requires for the components we need on our page var frame = require("ui/frame"); var Page = require("ui/page").Page; var StackLayout = require("ui/layouts/stack-layout").StackLayout; var Label = require("ui/label").Label; var Button = require("ui/button").Button;   // Create our required function which NativeScript uses // to build the page. exports.createPage = function() {   // Create our components for this page   var page = new Page();   var layout = new StackLayout();   var welcomeLabel = new Label();   var backButton = new Button();     // Assign our page title   page.actionBar.title = "Settings";   // Setup our welcome label   welcomeLabel.text = "You are now in Settings!";   welcomeLabel.cssClass = "message";     // Setup our Go Back button   backButton.text = "Go Back";   backButton.on("tap", function () {     frame.topmost().goBack();   });     // Add our layout items to our StackLayout   layout.addChild(welcomeLabel);   layout.addChild(backButton);     // Assign our layout to the page.   page.content = layout;   // Return our created page   return page; }; One thing I did want to mention here is that if you are creating a page totally programmatically without the use of a Declarative XML file, the createPage function must return the page component. The frame component is expected to have a Page component. Summary We have covered a large amount of foundational information in this article. We also covered which files are used for your application and where to find and make any changes to the project control files. In addition to all this, we also covered several foundational components such as the Application, Frame, and Page components. Resources for Article: Further resources on this subject: Overview of TDD [article] Understanding outside-in [article] Understanding TDD [article]
Read more
  • 0
  • 0
  • 1468

article-image-flexible-layouts-swift-and-uistackview-0
Milton Moura
04 Jan 2016
12 min read
Save for later

Flexible Layouts with Swift and UIStackview

Milton Moura
04 Jan 2016
12 min read
In this post we will build a Sign In and Password Recovery form with a single flexible layout, using Swift and the UIStackView class, which has been available since the release of the iOS 9 SDK. By taking advantage of UIStackView's properties, we will dynamically adapt to the device's orientation and show / hide different form components with animations. The source code for this post can the found in this github repository. Auto Layout Auto Layout has become a requirement for any application that wants to adhere to modern best practices of iOS development. When introduced in iOS 6, it was optional and full visual support in Interface Builder just wasn't there. With the release of iOS 8 and the introduction of Size Classes, the tools and the API improved but you could still dodge and avoid Auto Layout. But now, we are at a point where, in order to fully support all device sizes and split-screen multitasking on the iPad, you must embrace it and design your applications with a flexible UI in mind. The problem with Auto Layout Auto Layout basically works as an linear equation solver, taking all of the constraints defined in your views and subviews, and calculates the correct sizes and positioning for them. One disadvantage of this approach is that you are obligated to define, typically, between 2 to 6 constraints for each control you add to your view. With different constraint sets for different size classes, the total number of constraints increases considerably and the complexity of managing them increases as well. Enter the Stack View In order to reduce this complexity, the iOS 9 SDK introduced the UIStackView, an interface control that serves the single purpose of laying out collections of views. A UIStackView will dynamically adapt its containing views' layout to the device's current orientation, screen sizes and other changes in its views. You should keep the following stack view properties in mind: The views contained in a stack view can be arranged either Vertically or Horizontally, in the order they were added to the arrangedSubviews array. You can embed stack views within each other, recursively. The containing views are laid out according to the stack view's [distribution](...) and [alignment](...) types. These attributes specify how the view collection is laid out across the span of the stack view (distribution) and how to align all subviews within the stack view's container (alignment). Most properties are animatable and inserting / deleting / hiding / showing views within an animation block will also be animated. Even though you can use a stack view within an UIScrollView, don't try to replicate the behaviour of an UITableView or UICollectionView, as you'll soon regret it. Apple recommends that you use UIStackView for all cases, as it will seriously reduce constraint overhead. Just be sure to judiciously use compression and content hugging priorities to solve possible layout ambiguities. A Flexible Sign In / Recover Form The sample application we'll build features a simple Sign In form, with the option for recovering a forgotten password, all in a single screen. When tapping on the "Forgot your password?" button, the form will change, hiding the password text field and showing the new call-to-action buttons and message labels. By canceling the password recovery action, these new controls will be hidden once again and the form will return to it's initial state. 1. Creating the form This is what the form will look like when we're done. Let's start by creating a new iOS > Single View Application template. Then, we add a new UIStackView to the ViewController and add some constraints for positioning it within its parent view. Since we want a full screen width vertical form, we set its axis to .Vertical, the alignment to .Fill and the distribution to .FillProportionally, so that individual views within the stack view can grow bigger or smaller, according to their content.    class ViewController : UIViewController    {        let formStackView = UIStackView()        ...        override func viewDidLoad() {            super.viewDidLoad()                       // Initialize the top-level form stack view            formStackView.axis = .Vertical            formStackView.alignment = .Fill            formStackView.distribution = .FillProportionally            formStackView.spacing = 8            formStackView.translatesAutoresizingMaskIntoConstraints = false                       view.addSubview(formStackView)                       // Anchor it to the parent view            view.addConstraints(                NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[formStackView]-20-|", options: [.AlignAllRight,.AlignAllLeft], metrics: nil, views: ["formStackView": formStackView])            )            view.addConstraints(                NSLayoutConstraint.constraintsWithVisualFormat("V:|-20-[formStackView]-8-|", options: [.AlignAllTop,.AlignAllBottom], metrics: nil, views: ["formStackView": formStackView])            )            ...        }        ...    } Next, we'll add all the fields and buttons that make up our form. We'll only present a couple of them here as the rest of the code is boilerplate. In order to refrain UIStackView from growing the height of our inputs and buttons as needed to fill vertical space, we add height constraints to set the maximum value for their vertical size.    class ViewController : UIViewController    {        ...        var passwordField: UITextField!        var signInButton: UIButton!        var signInLabel: UILabel!        var forgotButton: UIButton!        var backToSignIn: UIButton!        var recoverLabel: UILabel!        var recoverButton: UIButton!        ...               override func viewDidLoad() {            ...                       // Add the email field            let emailField = UITextField()            emailField.translatesAutoresizingMaskIntoConstraints = false            emailField.borderStyle = .RoundedRect            emailField.placeholder = "Email Address"            formStackView.addArrangedSubview(emailField)                       // Make sure we have a height constraint, so it doesn't change according to the stackview auto-layout            emailField.addConstraints(                NSLayoutConstraint.constraintsWithVisualFormat("V:[emailField(<=30)]", options: [.AlignAllTop, .AlignAllBottom], metrics: nil, views: ["emailField": emailField])             )                       // Add the password field            passwordField = UITextField()            passwordField.translatesAutoresizingMaskIntoConstraints = false            passwordField.borderStyle = .RoundedRect            passwordField.placeholder = "Password"            formStackView.addArrangedSubview(passwordField)                       // Make sure we have a height constraint, so it doesn't change according to the stackview auto-layout            passwordField.addConstraints(                 NSLayoutConstraint.constraintsWithVisualFormat("V:[passwordField(<=30)]", options: .AlignAllCenterY, metrics: nil, views: ["passwordField": passwordField])            )            ...        }        ...    } 2. Animating by showing / hiding specific views By taking advantage of the previously mentioned properties of UIStackView, we can transition from the Sign In form to the Password Recovery form by showing and hiding specific field and buttons. We do this by setting the hidden property within a UIView.animateWithDuration block.    class ViewController : UIViewController    {        ...        // Callback target for the Forgot my password button, animates old and new controls in / out        func forgotTapped(sender: AnyObject) {            UIView.animateWithDuration(0.2) { [weak self] () -> Void in                self?.signInButton.hidden = true                self?.signInLabel.hidden = true                self?.forgotButton.hidden = true                self?.passwordField.hidden = true                self?.recoverButton.hidden = false                self?.recoverLabel.hidden = false                self?.backToSignIn.hidden = false            }        }               // Callback target for the Back to Sign In button, animates old and new controls in / out        func backToSignInTapped(sender: AnyObject) {            UIView.animateWithDuration(0.2) { [weak self] () -> Void in                self?.signInButton.hidden = false                self?.signInLabel.hidden = false                self?.forgotButton.hidden = false                self?.passwordField.hidden = false                self?.recoverButton.hidden = true                self?.recoverLabel.hidden = true                self?.backToSignIn.hidden = true            }        }        ...    } 3. Handling different Size Classes Because we have many vertical input fields and buttons, space can become an issue when presenting in a compact vertical size, like the iPhone in landscape. To overcome this, we add a stack view to the header section of the form and change its axis orientation between Vertical and Horizontal, according to the current active size class.    override func viewDidLoad() {        ...        // Initialize the header stack view, that will change orientation type according to the current size class        headerStackView.axis = .Vertical        headerStackView.alignment = .Fill        headerStackView.distribution = .Fill        headerStackView.spacing = 8        headerStackView.translatesAutoresizingMaskIntoConstraints = false        ...    }       // If we are presenting in a Compact Vertical Size Class, let's change the header stack view axis orientation    override func willTransitionToTraitCollection(newCollection: UITraitCollection, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {        if newCollection.verticalSizeClass == .Compact {            headerStackView.axis = .Horizontal        } else {            headerStackView.axis = .Vertical        }    } 4. The flexible form layout So, with a couple of UIStackViews, we've built a flexible form only by defining a few height constraints for our input fields and buttons, with all the remaining constraints magically managed by the stack views. Here is the end result: Conclusion We have included in the sample source code a view controller with this same example but designed with Interface Builder. There, you can clearly see that we have less than 10 constraints, on a layout that could easily have up to 40-50 constraints if we had not used UIStackView. Stack Views are here to stay and you should use them now if you are targeting iOS 9 and above. About the author Milton Moura (@mgcm) is a freelance iOS developer based in Portugal. He has worked professionally in several industries, from aviation to telecommunications and energy and is now fully dedicated to creating amazing applications using Apple technologies. With a passion for design and user interaction, he is also very interested in new approaches to software development. You can find out more at http://defaultbreak.com
Read more
  • 0
  • 0
  • 15637