Tuesday, 28 February 2012

Week5


This week I almost finish all the tutorial on the wordpress. It's already week 5 so next week i gonna start planning on my final project.
Static View
Static Table View displays predefined content only which normally could be create with the interface builder.

First create a new project drag a table view controller to the main view and change the table view behavior to a static cells. In my case i’m going to build a list of apple product, which categorize to Mac and iDevice and 2 section  and several row was customized through the 
Attributes Inspector


Dynamic Table View
Dynamic Table View displays dynamic content which is required to be loaded from code.  Which it will update the content automatically. data source methods have to implement to tell the table how many sections/rows it has, what to display in each row.

As usual Create a new project than drag a table view to the storyboard and make sure the table Attributes is a dynamic.

After that, we now need to create our own table view controller by creating UIViewController Subclass – UITableViewController.

Besides, I would like to create a custom layout for each table cell so another cellviewcontroller is needed. In here an UIImageView and UILabel outlet is created to display car image and car model in a cell.
//
//  carcell.m
//  DynamicTableView
//
//  Created by Chong Kin Ker on 25/02/2012.
//  Copyright (c) 2012 University Of Leeds. All rights reserved.
//

#import "carcell.h"

@implementation carcell
@synthesize carImage;
@synthesize carModel;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end
now need to create data model to be displayed in the. In this case I’m building a table list of Vehicle which is BMW and Mercedes. So I created few array to hold the Car Model and the model image name.
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.Mercedes = [NSArray arrayWithObjects:@"A Class",@"B Class",@"C Class",@"CL Class",@"CLS Class",@"E Class",@"M CLass"nil];
    self.BMW = [NSArray arrayWithObjects:@"1 Series",@"3 Series",@"5 Series",@"7 Series",@"X1",@"X3",@"X5",@"X6"nil];
    
    self.MercImages = [[NSArray alloc]
                      initWithObjects:@"a.jpg",
                      @"b.jpg",
                      @"c.jpg",
                      @"cl.jpg",
                       @"cle.jpg",
                       @"e.jpg",
                       @"m.jpg"nil];
    
    self.BMWImages = [[NSArray alloc]
                       initWithObjects:@"1.jpg",
                       @"3.jpg",
                       @"5.jpg",
                       @"7.jpg",
                       @"x1.jpg",
                       @"x3.jpg",
                       @"x5.jpg",
                      @"x6.jpg",nil];


}

In the below numberOfSectionsInTableView method, it return the number of section needed for the table in this case is 2 because there is only 2 brand.
- (
NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 2;
}

in the below 
tableView:numberOfRowsInSection: method that it returns the count of the array. I have to put if statement to determine which section to count first.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"section is %d",section);

    if (section==0)
        return [self.Mercedes count];
    
    else if (section ==1)
        return [self.BMW count];
    else 
    return 0;

}

After that I used titleForHeaderInSection method for the tittle for each section. In this case it is Mercedes-Benz and BMW.

- (
NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    //For each section, you must return here it's label
    if(section == 0
        return @"Mercedes-Benz"
    else if (section==1)
        return @"BMW"
    else 
        return 0;
            
}

  Below cellForRowAtIndexPath method finally display all the array data to tablecell.

    int section = [indexPath section];
    int row = [indexPath row];
   // NSLog(@"section%d",section);
  //  NSLog(@"row%d",row);

    if (section ==0){
        cell.carImage.image = [UIImage imageNamed
                               [self.MercImages objectAtIndex:row]];
    cell.carModel.text = [self.Mercedes objectAtIndex:row];
    }
    
    else if(section==1){
    cell.carImage.image = [UIImage imageNamed
                               [self.BMWImages objectAtIndex:row]];
    cell.carModel.text = [self.BMW objectAtIndex:row];
    }
        
    return cell;
     

After complete the table list, I added another emply view to display the information of each vehicle by navigation and pass data to the new view with the help of segue. But first a new view controller file have to be create and connect it to the new view as this call I call it “cardetail”. I first connect he table view and the detail view with navigationBar and call prepareForSegue method to pass data to the detail view before segue.

-(
void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        carDetails *detailViewController = 
        [segue destinationViewController];
        
        NSIndexPath *myIndexPath = [self.tableView                                   indexPathForSelectedRow];

        int section = [myIndexPath section];
        
       NSLog(@"section%d",section);
        
    if (section ==0){
        NSLog(@"Mercedes");
        detailViewController.carDetail = [[NSArray alloc]
                                               initWithObjects:
                                               [self.Mercedes objectAtIndex:[myIndexPath row]],
                                               [self.MercImages objectAtIndex:[myIndexPath row]],
                                               nil];
    }
        
    else if(section==1){
           NSLog(@"BMW");
        detailViewController.carDetail = [[NSArray alloc]
                                               initWithObjects:
                                               [self.BMW objectAtIndex:[myIndexPath row]],
                                               [self.BMWImages objectAtIndex:[myIndexPath row]],
                                               nil]; }

Multitouch, taps, and Gesture
Gesture is an umbrella term used to encapsulate any single interaction between the touch screen and the user, starting at the point that the screen is touched (by one or more fingers) and the time that the last finger leaves the surface of the screen. Swipes, pinches, stretches and flicks are all forms of gesture. A tap, as the name suggests, occurs when the user touches the screen with a single finger and then immediately lifts it from the screen. Taps can be single-taps or multiple-taps and the event will contain information about the number of times a user tapped on the screen.
First I create a project with simple layout design including some UILabel to to the mode of gesture and multitouch. Connect all the UILabel outlet, and start implement the code.

I used touchesBegan method so when a user touch the screen touchesBegan method will call. In this case i would like to capture the event type and display on the UILabel.

- (
void) touchesBegan:(NSSet *)touches 
            withEvent:(UIEvent *)event {
    NSUInteger touchCount = [touches count];
    NSUInteger tapCount = [[touches anyObjecttapCount];
    methodStatus.text = @"touchesBegan";
    touchStatus.text = [NSString stringWithFormat:
                        @"%d touches", touchCount];
    tapStatus.text = [NSString stringWithFormat:
                      @"%d taps", tapCount];
After that, Implement the touchesMoved method, will be call when finger moving on the surface on the screen. I the code below to monitor the activity.

- (
void) touchesMoved:(NSSet *)touches 
            withEvent:(UIEvent *)event {
    NSUInteger touchCount = [touches count];
    NSUInteger tapCount = [[touches anyObjecttapCount];
    methodStatus.text = @"touchesMoved";
    touchStatus.text = [NSString stringWithFormat:
                        @"%d touches", touchCount];
    tapStatus.text = [NSString stringWithFormat:
                      @"%d taps", tapCount];
}

Last, TouchesEnded method, it will be call when user remove the finger from the screen.
- (
void) touchesEnded:(NSSet *)touches 
            withEvent:(UIEvent *)event {
    NSUInteger touchCount = [touches count];
    NSUInteger tapCount = [[touches anyObjecttapCount];
    methodStatus.text = @"touchesEnded";
    touchStatus.text = [NSString stringWithFormat:
                        @"%d touches", touchCount];
    tapStatus.text = [NSString stringWithFormat:
                      @"%d taps", tapCount];
}


UIAccelerometerThe UIAccelerometer class enables us to get data from the onboard accelerometer.  You will have probably seen this many times, used for both game control as well as obtaining the device orientation.
First I designed a simply layout for this UIaccelerometer demo. Insert all the UILabel and stuff needed to a view.
After creating needed outlet and action,  I started to implement the UIaccelerometer. First  I have to create a shared instance in viewDidload.

    
UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
    accelerometer.updateInterval = 1.0/50.0;
    accelerometer.delegate = self;

after that UIAccelerometerDelegate protocol also need to the class. So @interface ViewController : UIViewController<UIAccelerometerDelegate>
are needed in the header file.

After that simply implement the On off switha dn slider to update the update interval frequency for the UIaccelerometer. 

- (IBAction)mySwitch:(UISwitch *)sender {
    UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
    if(sender.on){
        accelerometer.delegate = self;
    }
    else accelerometer.delegate = nil;
}

- (IBAction)mySlider:(UISlider *)sender {
    UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
    float sliderValue = self.mySlider.value;
    accelerometer.updateInterval = sliderValue;
}

use didaccelerate method to use get data from the accelerometer. In my case, I display all the data to UILabel.
- (
void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    self.displayX.text = [NSString stringWithFormat:@"%f",acceleration.x];
    self.displayY.text = [NSString stringWithFormat:@"%f",acceleration.y];
    self.displayZ.text = [NSString stringWithFormat:@"%f",acceleration.z];
    }
CLLocationManager
Core Location framework which uses the on-board hardware to obtain this data such as GPS, wifi, 3G compass for the most accurate location.

Before start create a project as usual, but this time CoreLocation framework have to link to the project because it is not there as default.  The framework can be added by “linked Frameworks and Libraries Window” section. After that do remember to import the framework to the view controller.
#import <CoreLocation/CoreLocation.h>

I than design a simply layout for this demo tutorial. By adding lot of UIlabel to display the data obtain from the onboard hardware
After that create outlet for UIlabel as usual. Abd create a property to store the location manager.

@property(nonatomic,strongCLLocationManager *locManager;

after that alloc and init the instance of the CLLocationManager class and create delegate to self controller.  Property desiredAccuray is to determine to mode used for the cllocationMangaer Class. Setup a distance filter and start updating the current location.
    if (self.locManager == nil) {
        self.locManager = [[CLLocationManager allocinit];
    }
    self.locManager.delegate = self;
    self.locManager.desiredAccuracy = kCLLocationAccuracyBest;
    self.locManager.distanceFilter = 10.0;
    self.locManager.purpose = @"To obtain data from Hardware";
    [self.locManager startUpdatingLocation];
    
    if ([CLLocationManager headingAvailable] == YES) {
        self.locManager.headingFilter = 1;
        [self.locManager startUpdatingHeading];
    }
    
locationManager:didUpdateToLocation:fromLocation: is a method that process the location and heading data.

The code below display all the heading data and location.
- (
void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation*)oldLocation{
    NSLog(@"Lon = %f Lat = %f", newLocation.coordinate.longitude,newLocation.coordinate.latitude);
    
     NSLog(@"Speed = %f", newLocation.speed);
 //   self.displayLong.text = newLocation.timestamp;

    self.displayAlt.text = [NSString stringWithFormat:@"%f",newLocation.altitude];
    self.displayLong.text = [NSString stringWithFormat:@"%f",newLocation.coordinate.longitude];
    self.displayLat.text = [NSString stringWithFormat:@"%f",newLocation.coordinate.latitude];
    self.displayCourse.text = [NSString stringWithFormat:@"%f",newLocation.altitude];
    self.displayHoriz.text = [NSString stringWithFormat:@"%f",newLocation.horizontalAccuracy];
    self.displayVert.text = [NSString stringWithFormat:@"%f",newLocation.verticalAccuracy];
    self.displayTime.text = [NSString stringWithFormat:@"%@",newLocation.timestamp];
    self.displaySpeed.text = [NSString stringWithFormat:@"%f",newLocation.speed];

}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    NSLog(@"True Heading = %f Mag = %f", newHeading.trueHeading,
          newHeading.magneticHeading);
    self.displayMag.text = [NSString stringWithFormat:@"%f",newHeading.magneticHeading];
    self.displayTrue.text = [NSString stringWithFormat:@"%f",newHeading.trueHeading];

}

I would like to add 
CLGeocode
in this section since they are related.

The CLGeocode class allows us to convert between co-ordinates and human-readable data such as street name, city, country etc.

First create a private instance to store the location.
@interface ViewController () 
@property (nonatomic,strongCLLocation *myLocation;
@end

self
.myLocation = newLocation; // store Newlocation for geocode


Next, Implement the CLGeocode in an button action when the button was pressed to show geocode. The code below, first alloc and init an instance of the CLGeocoder class and then start the reverse geocoding process using our stored location.  The results are stored in an NSArray.  thn check if the array contains an entry  and if it does, create a CLPlacemark object using the first object in the array.

- (IBAction)geocodePressed:(UIButton *)sender {
    CLGeocoder *myGeocoder = [[CLGeocoder allocinit];
    [myGeocoder reverseGeocodeLocation:self.myLocation completionHandler:
     ^(NSArray* placemarks, NSError* error){
         if ([placemarks count] > 0){
             CLPlacemark *myPlacemark = [placemarks objectAtIndex:0];
             self.addressName.text = myPlacemark.name;
            self.Address.text = myPlacemark.locality;
         self.postcode.text = myPlacemark.postalCode;
         self.Country.text = myPlacemark.country;}}];
}



MKMapView + Annoation
The map view enables us to embed a Google map into our app.  As well as showing the user location and being able to track any movement, the map has various gestures built in, such as pinch to zoom, scrolling etc.

First and foremost, Create a new project as usual and create outlet for mapview found from the library.  AFter that connect delegate to the owner file and check Attributes Inspector for the MapView behavior. In this case, I would like to to build a Map View that include a locate button and Map mode so i can leave shows user location untick and leave everything as default.

Now i than design a simply layout for the map interface. I added a toolbar to enable and refresh my location and added a semi transparent button to change the map mode
In the header code side, include the Map kit library and comform to the delegate protocol.
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface ViewController : UIViewController <MKMapViewDelegate>
After that i include the code below to update the center coordinate to the location of user.
#pragma mark - MapKit Delegate Methods

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
    self.map.centerCoordinate = userLocation.location.coordinate;
}

Now I have done with the Map. Let implement the button for refresh and Map mode. I used the set:Region method to zoom to the region of the user location.

- (
IBAction)mapMode:(UIButton *)sender {

   if (map.mapType == MKMapTypeStandard)
        map.mapType = MKMapTypeSatellite;
else if (map.mapType == MKMapTypeSatellite)
        map.mapType = MKMapTypeHybrid;
    else map.mapType = MKMapTypeStandard;

}
- (IBAction)refresh:(UIBarButtonItem *)sender {
    map.showsUserLocation = YES;
    MKUserLocation *userLocation = map.userLocation;
    MKCoordinateRegion region =
    MKCoordinateRegionMakeWithDistance (
                                        userLocation.location.coordinate100100);
    [map setRegion:region animated:YES];

}

Besides, i also added Annotation point to the school of electrical and electronic of university of leeds.
  CLLocationCoordinate2D annotationCoord;
    
    annotationCoord.longitude = -1.554586;
    annotationCoord.latitude = 53.809638;
    
    MKPointAnnotation *annotationPoint = [[MKPointAnnotation allocinit];
    annotationPoint.coordinate = annotationCoord;
    annotationPoint.title = @"University of Leeds";
    annotationPoint.subtitle = @"School of Electronic & Electrical Engineering";
    [map addAnnotation:annotationPoint]; 

The screenshot is when the app launch. Displaying the map of united kingdom.

Once i touched on the refresh button the map will enable my GPS and locate my current location. In the same time, it will zoom to the location region within 100meter.

When the mode button on the top of the view is touch, The map will change from Map Mode to Satellite Mode and than hybrid mode.

The screen shot below is my current location and annotation for university of leeds

No comments:

Post a Comment