Thursday, June 25, 2015

UIPanGestureRecognizer - Moving a ball(UIImage) with the pan gesture programmatically

Update: July 8, 2017 (Swift 3.1 + Xcode 8.3.3)
Update: July 18, 2016 (Swift 2.2 + Xcode 7.3.1)
Original Post: June 25, 2015

1. Add an image file named ball.png to the project. 

2. Modify your ViewController.swift as below by enabling either Method 1 or Method 2.

Update: July 8, 2017 (Swift 3.1 + Xcode 8.3.3)


import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myImageView = UIImageView(image: UIImage(named: "ball.png"))
        myImageView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
        
        myImageView.isUserInteractionEnabled = true
        //Must be enabled for tap events
        
        view.addSubview(myImageView)
        //Add an image programmatically
        
        let myPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(myPanAction)//Update: July 18, 2016 for Xcode 7.3.1(Swift 2.2)
        
        myPanGestureRecognizer.minimumNumberOfTouches = 1
        myPanGestureRecognizer.maximumNumberOfTouches = 1
        
        myImageView.addGestureRecognizer(myPanGestureRecognizer)
    }
    
    //Method 1:
    /*func myPanAction(recognizer: UIPanGestureRecognizer) {
        let translation = recognizer.translation(in: self.view)
            if let myView = recognizer.view {
            myView.center = CGPoint(x: myView.center.x + translation.x, y: myView.center.y + translation.y)
        }
            recognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
    }*/
    
    //Method 2:
    func myPanAction(recognizer: UIPanGestureRecognizer) {
        if ((recognizer.state != UIGestureRecognizerState.ended&&
            (recognizer.state != UIGestureRecognizerState.failed)) {
            recognizer.view?.center = recognizer.location(in: recognizer.view?.superview)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

Update: July 18, 2016 (Swift 2.2 + Xcode 7.3.1)

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myImageView = UIImageView(image: UIImage(named: "ball.png"))
        myImageView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
        
        myImageView.userInteractionEnabled = true
        //Must be enabled for tap events
        
        view.addSubview(myImageView)
        //Add an image programmatically
        
        let myPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(myPanAction)) //Update: July 18, 2016 for Xcode 7.3.1(Swift 2.2)
        
        myPanGestureRecognizer.minimumNumberOfTouches = 1
        myPanGestureRecognizer.maximumNumberOfTouches = 1
        
        myImageView.addGestureRecognizer(myPanGestureRecognizer)
    }
    
    //Method 1:
    /*func myPanAction(recognizer: UIPanGestureRecognizer) {
        let translation = recognizer.translationInView(self.view)
        if let myView = recognizer.view {
            myView.center = CGPoint(x: myView.center.x + translation.x, y: myView.center.y + translation.y)
        }
        recognizer.setTranslation(CGPointZero, inView: self.view)
    } */
    
    //Method 2:
    func myPanAction(recognizer: UIPanGestureRecognizer) {
        if ((recognizer.state != UIGestureRecognizerState.Ended) &&
        (recognizer.state != UIGestureRecognizerState.Failed)) {
            recognizer.view?.center = recognizer.locationInView(recognizer.view?.superview)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

Note: you may enable either Method 1 or Method 2.

3. The result:


Tuesday, June 23, 2015

UITableViewCell - Custom Prototype Cell in UITableView with the storyboard

This is a TableView Prototype Cell Tutorial.

0. Keep the default Auto Layout and Size Classes settings in the storyboard file inspector.


1. Drag a table view to the view controller of the storyboard and then drag a table view cell into the table view.

2. Select the table view cell and set the identifier in attribute inspector as myCellIdentifier.


3. Create a new file.  Select iOS/Source/Cocoa Touch Class and next. Name the class as MyTableViewCell and a subclass of UITableViewCell.

3. Go back to the storyboard. Select myCellIdentifier (formerly the table view cell). Select the identity inspector and select MyTableViewCell as the class.


4. Drag two labels into the prototype cell. Control-drag the labels into the MyTableViewCell.swift file.

    @IBOutlet weak var myLabel1: UILabel!
    @IBOutlet weak var myLabel2: UILabel!

5. In ViewController.swift, change the class type to UITableViewController:


class ViewController: UITableViewController {

6. Complete the ViewController.swift file as below:

import UIKit

class ViewController: UITableViewController {
    
    var myArray = ["AAA", "BBB", "CCC", "DDD"]
    
    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.
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myArray.count
    }
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("myCellIdentifier", forIndexPath: indexPath) as! MyTableViewCell
            cell.myLabel1.text = myArray[indexPath.row]
            cell.myLabel2.text = "\(indexPath.row)"
        return cell
    }
}

MyTableViewCell.swift is:

import UIKit

class MyTableViewCell: UITableViewCell {

    
    @IBOutlet weak var myLabel1: UILabel!
    @IBOutlet weak var myLabel2: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

7. Add two images to the table cell as below:

8. Add width and height constraints to the two images:


Control-drag the top image icon to the top and select "Top Space to Container Margin".
Control-drag the top image icon to the right, and control-drag the bottom image to the right and to the bottom. Select the top option each time. 

The ViewController Scene becomes:


9. Run the app and the result is:



==================================

UITableViewCell - Create Custom Prototype Table Cell in UITableView Programmatically (without using the Storyboard)

MKMapView - Map without using the Storyboard

1. Add MapKit and CoreLocation frameworks to the project targets.



2. Complete the code as below:

import UIKit
import CoreLocation
import MapKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        var myMapView = MKMapView(frame: self.view.bounds)
        
        myMapView.mapType = MKMapType.Standard
        
        self.view.addSubview(myMapView)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

Monday, June 22, 2015

Draw UITableView programmatically (without using the Storyboard)

Update: May 27, 2017 - Xcode 8.3.2 (Swift 3.1)
Update: March 28, 2016 - Xcode 7.3 (Swift 2.2)

To draw a table in iOS without using the storyboard, simply create a Single View Application project and modify ViewController.swift as below:

Xcode 8.3.2 (Swift 3.1)

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
       
        let tableView = UITableView(frame: CGRect(x: 20, y: 50, width: 200, height: 400), style: UITableViewStyle.plain)
        tableView.dataSource = self
        tableView.delegate = self
        view.addSubview(tableView)
    }
   
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
   
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "myIdentifier")
        cell.textLabel?.text = "\(indexPath.row)"
        cell.detailTextLabel?.text = "Subtitle"
       
        return cell
    }

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

Xcode 7.3 (Swift 2.2)

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tableView = UITableView(frame: CGRectMake(20, 50, 200, 400), style: UITableViewStyle.Plain)
        tableView.dataSource = self
        tableView.delegate = self
        view.addSubview(tableView)
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "myIdentifier")
        cell.textLabel?.text = "\(indexPath.row)"
        cell.detailTextLabel?.text = "Subtitle"
        
        return cell
    }

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

}

Result:

*****************************

Saturday, June 13, 2015

Remote / Push Notification

This is a tutorial to remote / push notifications.

1. Create a single view application project in Xcode. Select 'Swift' as the language.

2. Disable 'Use Auto Layout' in the storyboard file inspector.


3. Register notification types (user notification settings) and remote notifications by modifying function application in AppDelegate.swift as below:
    
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        
        let myNotificationType = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound

        application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: myNotificationType, categories: nil))
        
        application.registerForRemoteNotifications()
        
        return true
    }

4. Add the following codes to AppDelegate.swift:


    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
        println("didRegisterForRemoteNotificationsWithDeviceToken: \(deviceToken)")
    }
    func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
        println("didFailToRegisterForRemoteNotificationsWithError: \(error)")

    }


5. Select Finder/Applications/Utilities/Keychain Access


Select Keychain Access/Certificate Assistant/Request a Certificate From a Certificate Authority...


Enter the Certificate Information and save the certificate to disk.


6. Go to the Apple Developer website. Choose the Member Center and sign in. Choose Certificates, Identifiers & Profiles.



Choose iOS Apps\Identifiers.


Click the '+' sign at the top right and enter the App ID Description:


Enter the Explicit App ID.


In App Services section, enable 'Push Notifications'.

Confirm the App ID and press 'Submit'.

Select the App ID just created and select 'Edit'. 

The Push Notifications item is shown as configurable:
Select 'Create Certificate...' under Development SSL Certificate.


Select 'Choose File...' and choose the .certSigningRequest file just downloaded.
Select 'Generate'.

Select Download.

Double click the file just downloaded.

7. Select 'Provisioning Profile' and 'All'.

Select '+' and 'iOS App Development'.

Press 'Continue' and enter the profile name in the Generate state.

Download the provisioning profile.

7. In Keychain Access, select 'My Certificates', then right click on the certificate just created. Select Export. Enter the passwords if required.  


This saves the exported file to the Personal Information Exchange (p12) format.


8. Open Xcode. Run the app with an iPhone/iPad, not the iOS simulator. It should print out:

didRegisterForRemoteNotificationsWithDeviceToken: <0b8c765e 19056ab3 ....

Keep this device token since it will be used later in the push Java file.

9. Enable the terminal by finding it at Applications/Utilities/Terminal.

Type nano in the command line. Save the file as *.java. You may use nano to edit the file. I prefer to use XCode.

The Java file is edited as below:


import java.io.*;
import com.notnoop.apns.*;

public class MyPush
{
public static void main(String[] args)
{
        String myCertPath = "RemoteNotificationP12.p12";
        String myPassword = "mypassword";
        String myToken = "0b8c765e19056ab34f4f609dd8ec37...";
        
        ApnsService service =
APNS.newService()
.withCert(myCertPath,myPassword)
.withSandboxDestination()
.build();
String myPayload = APNS.newPayload()
.alertBody(args[0])
            .badge(1)
            .sound("default")
.build();
service.push(myToken, myPayload);
}

}

Note that the space characters within the device token have to be removed.


10. Download apns-0.1.5-jar-with-dependencies.jar. Put it in together with *.java and *.p12 files in the same folder.

11. In the terminal, go to the directory of the three files. Compile the Java file with the javac command:

javac -cp apns-0.1.5-jar-with-dependencies.jar MyPush.java

Now the *.class file is created.



Then run the *.java file with the java command in the terminal:

java -cp apns-0.1.5-jar-with-dependencies.jar: MyPush "Hot News 123"

The iPad / iPhone should receive the push notification. There should be an alarm sound and an updated badge number.