Website Links

Friday, 13 January 2017

React Native #4 - Props

Props allow you to make a component with that is reused throughout your app with slightly different properties. This can be referred to from your custom component's render function:

  import React, { Component } from 'react';
  import { Text } from 'react-native';

  class MessageView extends Component {
    render() {
      return (
        {this.props.message}
      );
    }
  }


Note: {this.props.message} is surrounded by braces to embed it into JSX.
You could then utilise your reusable component by importing and adding the following to another component:
<MessageView message="Hello World! />

Thursday, 12 January 2017

React Native #3 - Flexbox Basics

Laying out components in React Native is done using flexbox, the key difference though is that style names are written camelcase e.g. background-color would be backgroundColor when defining it as part of a React Native Stylesheet. Today, I'll take you through the key ways you can layout your components using flexbox:

Parent Properties

display: flex;

In web dev, if you want to layout your page using flexbox you will need to specify "display: flex;" in your style for that HTML element. However, in react native this is unnecessary.

flexDirection

  • row (default): layout child components left to right
  • row-reverse: layout child components right to left
  • column: layout child components top to bottom
  • column-reverse: layout child components bottom to top


flexWrap

  • nowrap (default): components try to fit on one line
  • wrap: components can wrap onto new line (left to right)
  • wrap-reverse: components can wrap onto new line (right to left)


flexFlow

Shorthand for flexDirection and flexWrap e.g. column wrap

justifyContent

Distributes space left over once all the child items have been rendered.
  • flex-start: components are rendered at the start of the parent
  • flex-end: components are rendered at the end of the parent
  • center: components are rendered at the center of the parent
  • space-between: components are rendered equidistant apart, with a component aligned with both the start and end of the parent component
  • space-around: components are rendered equidistant apart, with a space at before the first and last component


alignItems

How components are aligned vertically for row layout or horizontally for column layout:
  • flex-start: aligned with the top of the parent layout for row, and with the left of the parent for column
  • flex-end: aligned with the bottom of the parent layout for row, and with the right of the parent for column
  • center: centered within the parent element
  • stretch: components stretch to fill the parent element (respects min/max width/height)
  • baseline: components are aligned along their baselines


alignContent

Similar to justifyContent but vertically for row and horizontally for column. It has the same potential values as justifyContent.

Child Properties

order

Takes an integer value, and defines the order components appear in the container. By default, this is based off the components order in the HTML.

flexGrow

A unitless number that dictates what amount of space an item should take up in a flex container as a proportion.

flexShrink

Similar to flexGrow except it specifies the items ability to shrink if necessary.

flex

Combination of flexGrow, flexShrink and flexBasis (in that order e.g. 0 1 auto). flexShrink and flexBasis are optional.

alignSelf

Allows the alignment specified by alignItems to be overridden for the specific child item. It shares the same potential values as alignContent.

References

Comprehensive Flexbox Tutorial

Wednesday, 11 January 2017

React Native #2 - Creating Components

In this post, I will take you through how to create a component that is reusable in iOS/Android. First off, we will make a folder where we place all our reusable code, I have called it app and created it under the folder that was created when using the react-native command to initialise your app. There will be a few different things that go in this folder, so I have created another folder under app called components.

ViewContainer Component

I have chosen a simple component for the purpose of this tutorial, and it is a ViewContainer component. It is effectively a react native view, with specified styling applied and will form the base of all the screens you add to your app. Under app/components I add a new folder called viewContainer with 2 new files, the first file defines how the component is rendered and is called viewContainer.js:

  'use strict';

  import React, { Component } from 'react';
  import { View } from 'react-native';
  import styles from './style';

  class ViewContainer extends Component {
      render() {
          return (
              <View style={styles.viewContainer}>
                  {this.props.children}
              </View>
          );
      }
  }

  module.exports = ViewContainer;


The first file imports React and Component, React is a default export (see here for explanation) and so doesn't need to be in {}. We import Component so that we can define a new component and how it is rendered, this is defined in the render function. We also import View from react native, as this is the type of existing component we want to base our custom component off. And finally, we also import the style for the view container which is called style.js:

  'use strict';
  import { StyleSheet } from 'react-native';

  const styles = StyleSheet.create({
      viewContainer: {
          flex: 1,
          flexDirection: "column",
          justifyContent: "center",
          alignItems: "stretch"
      }
  });

  module.exports = styles;


The second file imports StyleSheet from react native, which can be used to define the style of the view component using flexbox CSS.

Using the ViewContainer Component

Your ViewContainer component can be used by either Android or iOS, so in either your index.ios.js or index.android.js or both, you can change the file to be:

  import React, { Component } from 'react';
  import {
    AppRegistry,
    StyleSheet,
    Text
  } from 'react-native';

  import ViewContainer from 
    './app/components/viewContainer/ViewContainer';

  export default class Goalie extends Component {
    render() {
      return (
        <ViewContainer>
          <Text style={styles.welcome}>
            Welcome to React Native!
          </Text>
          <Text style={styles.instructions}>
            To get started, edit index.ios.js
          </Text>
          <Text style={styles.instructions}>
            Press Cmd+R to reload,{'\n'}
            Cmd+D or shake for dev menu
          </Text>
        </ViewContainer>
      );
    }
  }

  const styles = StyleSheet.create({
    welcome: {
      fontSize: 20,
      textAlign: 'center',
      margin: 10
    },
    instructions: {
      textAlign: 'center',
      color: '#333333',
      marginBottom: 5
    },
  });

  AppRegistry.registerComponent('Goalie', () => Goalie);

Monday, 9 January 2017

React Native #1 - Getting Started!

Hi everyone, React Native is a cool framework I've been learning about lately that lets you build mobile apps using Javascript. So over the next few weeks I will document my efforts with developing apps in React Native!

Getting Started

Just follow the React Native Getting Started guide to download everything you require. Note: iOS apps can only be developed on a Mac. I will be developing an app for both Android and iOS over this series so will be using a Mac. If you get errors, you may need to update node/npm if you have previously installed these.

Initialising the App

  1. In your terminal, change to your development directory or where you want your react native project to be saved.
  2. Enter the command
    react-native init [project_name]
    This will setup your React Native project
  3. Enter the command
    cd [project_name]
  4. Enter the command
    react-native run-ios
    from inside your React Native project directory to see the base iOS output
  5. To see the base Android output:
    1. Open the android folder in Android studio
    2. Go to Tools > Android > AVD Manager and setup a device, this will handle installing anything you need for the emulator to run
    3. Run the virtual device you created
    4. Enter the command
      react-native run-android
      from inside your React Native project directory to see the base Android output


Editing the view

You can edit the view displayed in the index.android.js and index.ios.js files in your preferred text editor.

Swift - Adding a Leaderboard to an App with GameKit

GameKit makes it really easy to add global scoreboards to an app, where you can compare yourself to Game Center friends or everyone who has played on the all time scoreboard. This article will take you through how to add it to your apps.

Initial Setup

First, go to iTunes Connect and select your app, and then click features. It should look something like this:



Then click on the plus next to leaderboards and select "Single Leaderboard". You should now be at a page that looks like this:



Fill out the fields, the Leaderboard Id will be how you reference it in the code. Ensure you also add a language, the name here will be the name that appears to users viewing your scoreboard:



Once you are done click save, and ensure that Game Center is enabled for your app against the build you are setting up. Then you will need to also enable it via Xcode. Open Xcode and ensure that GameKit is added as a Linked Framework/Library:



Finally, check the capabilities to ensure Game Center is successfully enabled:



Coding a Leaderboard

First, ensure the user is logged in when they first open the application by authenticating the player in the viewDidLoad function on one of the initial ViewController's presented by the application. Ensure the state of whether game center is enabled or not is saved, as this will allow you whether to show the option to view leaderboard after a user has played your game. For convenience and code simplicity, gameCenterEnabled is a global variable in this example.

  import UIKit
  import GameKit

  class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        score = 1
        // Do any additional setup after loading the view,
        // typically from a nib.
        authenticateLocalPlayer()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func authenticateLocalPlayer() {
        let localPlayer = GKLocalPlayer.localPlayer()
    
        localPlayer.authenticateHandler = {(ViewController, error) 
          -> Void in
            if((ViewController) != nil) {
                // 1 Show login if player is not logged in
                self.present(ViewController!, animated: true, 
                             completion: nil)
            } else if (localPlayer.isAuthenticated) {
                // 2 Player is already authenticated & logged in
                gameCenterEnabled = true
            } else {
                // 3 Game center is not enabled on the users device
                gameCenterEnabled = false
            }
    
        }
    }
  }



Next, you will want a view with a button to show the leaderboard , the view controller for this view should implement GKGameCenterControllerDelegate and handle dismissal and opening of the leaderboard. In this example saving of the score happens here as this view is displayed upon game completion. However, saving of the score can happen anywhere in your application.

  import UIKit
  import GameKit

  class ResultViewController: UIViewController, 
                              GKGameCenterControllerDelegate {
    @available(iOS 6.0, *)
    public func gameCenterViewControllerDidFinish(_ 
      gameCenterViewController: GKGameCenterViewController) {
        gameCenterViewController.dismiss(animated: false, 
                                         completion: nil)
    }
  
    override func viewDidLoad() {
        super.viewDidLoad()
        saveScore()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    // save score to leaderboard with matching id 
    func saveScore() {
        if (gameCenterEnabled) {
            let leaderboardID = "com.tripwire.memorymasterminds"
            let scoreToRecord = GKScore(leaderboardIdentifier: 
                                        leaderboardID)
            scoreToRecord.value = Int64(score)
            
            GKScore.report([scoreToRecord], 
                           withCompletionHandler: nil)
        }
    }
    
    // display leaderboard with matching id 
    @IBAction func showLeaderboardClicked(sender: AnyObject) {
        let gcVC = GKGameCenterViewController()
        gcVC.gameCenterDelegate = self
        gcVC.viewState = GKGameCenterViewControllerState
                             .leaderboards
        gcVC.leaderboardIdentifier = 
          "com.tripwire.memorymasterminds"
        self.present(gcVC, animated: false, completion: nil)
    }
    
  }

Tuesday, 6 December 2016

C# Generics


  • Used to not be generics and this gave you one of two options:
    • Use object as the type everywhere, but this had a performance penalty in that casting would have to be performed to get the actual object type
    • Duplicate code for different types
  • Most developers will be mmore frequently using generics as opposed to creating them, but if you wanted to create a generic class you would use public class Generic<T>
  • The generic collections are one of the commonly used inbuilt generics
  • Can restrict generic type e.g. public T Max<T>(T a, T b) where T : IComparable, so that only IComparable objects can be used in the generic method
  • Can have generic methods in non generic classes, just need to specify the generic at method level if it's not specified at class level
  • Generic constraint types:
    • where T : IComparable; T implements the IComparable interface
    • where T : Product; T is of type Product or any of its children
    • where T : struct; T is a value type, a use case for this is a nullable int implementation
    • where T : class; T is a reference type
    • where T : new(); T has a default constructor, a use case for this is when you want to instantiate a generic object
  • Can chain constraints e.g. where T : IComparable, new()

References

C# Generics

Wednesday, 23 December 2015

Swift - Local Notifications

There are several sorts of notifications a user can receiver in iOS, these are:
  • Lock screen notifications
  • Banner notifications
  • Alerts
Lock screen and banner notifications are quite compact and can only have 2 associated actions. Whereas alert notifications are larger and can have up to 4 actions. You can choose whether you want to receive banner notifications or alert notifications for an app by going to Settings > Notifications > [App name]. This article is aimed at teaching you how to schedule and cancel local notifications.

Notification Settings

In the App.delegate you can configure the settings for your notifications, e.g. what actions there will be and whether the action will take place in the background or visibly. Firstly, we need to be aware of what type of notifications we can have:
  • UIUserNotificationType.None: The user sees nothing when the notification is received
  • UIUserNotificationType.Badge: The user will see a number on the app icon that represents a number of unhandled notifications
  • UIUserNotificationType.Sound: The user will hear a sound when the notification is received
  • UIUserNotificationType.Alert: A banner notification, lock screen notification or alert notification will be displayed

Here is how the code for setting up a notification would look, a good place to do this is the App.delegate:

  func application(application: UIApplication, 
    didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) 
    -> Bool {
        // Override point for customization after application launch.      
        let types = UIUserNotificationType([UIUserNotificationType.Alert, 
          UIUserNotificationType.Badge])
        
        let emailAction = UIMutableUserNotificationAction()
        emailAction.destructive = false
        emailAction.authenticationRequired = false
        emailAction.activationMode = UIUserNotificationActivationMode
          .Foreground
        emailAction.identifier = "EMAIL"
        emailAction.title = "Send Email"
        
        let textAction = UIMutableUserNotificationAction()
        textAction.destructive = false
        textAction.authenticationRequired = false
        textAction.activationMode = UIUserNotificationActivationMode
          .Foreground
        textAction.identifier = "TEXT"
        textAction.title = "Send Text"
        
        let noneCategory = UIMutableUserNotificationCategory()
        noneCategory.identifier = "NONE"
        noneCategory.setActions([], forContext: 
          UIUserNotificationActionContext.Default)
        noneCategory.setActions([], forContext: 
          UIUserNotificationActionContext.Minimal)

        let emailCategory = UIMutableUserNotificationCategory()
        emailCategory.identifier = "EMAIL"
        emailCategory.setActions([emailAction], forContext:
          UIUserNotificationActionContext.Default)
        emailCategory.setActions([emailAction], forContext:
          UIUserNotificationActionContext.Minimal)

        let textCategory = UIMutableUserNotificationCategory()
        textCategory.identifier = "TEXT"
        textCategory.setActions([textAction], forContext:
          UIUserNotificationActionContext.Default)
        textCategory.setActions([textAction], forContext:
          UIUserNotificationActionContext.Minimal)

        let bothCategory = UIMutableUserNotificationCategory()
        bothCategory.identifier = "BOTH"
        bothCategory.setActions([textAction, emailAction], 
          forContext: UIUserNotificationActionContext.Default)
        bothCategory.setActions([textAction, emailAction;], 
          forContext: UIUserNotificationActionContext.Minimal)
        
        let settings :UIUserNotificationSettings = 
          UIUserNotificationSettings(forTypes: types, 
          categories: [noneCategory, emailCategory, 
                       textCategory, bothCategory])
        UIApplication.sharedApplication()
          .registerUserNotificationSettings(settings)
        
        return true
    }

The UIMutableUserNoticationCategory is something you can use when scheduling a new notification to specify what actions are available to it. The context for the actions can either be Default (up to 4) or Minimal (up to 2).

Scheduling a Notification

Scheduling a notification is incredibly simple and can be done as follows:

  let notification = UILocalNotification()

  \\ When the notification will appear
  notification.fireDate = dueDate

  \\ What the notification will say
  notification.alertBody = "Hello world"

  \\ Links what actions the notification will have with what was 
  \\ specified in the App.delegate
  notification.category = "BOTH"

  \\ Additional info that we need when the app receives a user's 
  \\ interaction with the notification
  var userInfo = [String: String]()
  userInfo["notificationId"] = bookToSave.objectID.persistentStore?
    .identifier
  notification.userInfo = userInfo
  
  UIApplication.sharedApplication()
    .scheduleLocalNotification(notification)


Cancelling a notification

Often, if a user has specified a due date for something and they edit it this you will need to cancel the existing notification and reschedule it. Finding the correct notification to cancel can sometimes be challenging and this is commonly where I rely on the userInfo I have passed to the notification:

  for notification in UIApplication.sharedApplication()
    .scheduledLocalNotifications! 
  {
    var userInfo = notification.userInfo as! [String : String]
    if (userInfo["notificationId"] == 
        bookToSave.objectID.persistentStore?.identifier) {
      UIApplication.sharedApplication()
        .cancelLocalNotification(notification)
    }
  }

It is also possible to cancel all notifications using UIApplication.sharedApplication().cancelAllLocalNotifications().

Handling actions of a notification

To handle receiving information from a notification, you will need to add the following function to your App.delegate:

  func application(application: UIApplication, 
    handleActionWithIdentifier identifier: String?, 
    forLocalNotification notification: UILocalNotification, 
    completionHandler: () -> Void)
  {
    if (identifier == "EMAIL") {
      NSNotificationCenter.defaultCenter()
        .postNotificationName("EmailPressed", object: nil)
    } else if (identifier == "TEXT") {
      NSNotificationCenter.defaultCenter()
        .postNotificationName("TextPressed", object: nil)
    }
        
    completionHandler()
  }

The method above is the first step, what it does is it gives you what action was pressed in the notification, along with the notification and a completion handler. You can then use the NSNotificationHandler to pass information to pass control to the view controller that will handle the actions. Here is an example of the notifications being handled in a view controller:

  override func viewDidLoad() {
    super.viewDidLoad()
    ...
        
    NSNotificationCenter.defaultCenter().addObserver(self, 
      selector: "sendEmail:", 
      name: "EmailPressed", 
      object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, 
      selector: "sendText:",
      name: "TextPressed",
      object: nil)
  }

  func sendEmail(notification : NSNotification) {
    ...
  }

  ...

The selector represents the method that will be called when the view controller received the event of the specified name. ':' after the method name represents that the method has a parameter.