Showing posts with label iOS Tutorial. Show all posts
Showing posts with label iOS Tutorial. Show all posts

Thursday, January 10, 2013

Page Control for Switching Between Views

This is a tutorial request from Ze Kitez.

As much as possible, I tried to do everything in Interface Builder, but sadly, some of the logic could not be done in IB.

1. Create a New Xcode Project, choose Single View Application template.


A ViewController will be created for us.

I'm using the latest Xcode up to date, so you may see a longer UIView in our xib file (for iPhone 5 devices). But if you want the old UIView size, you may change it by choosing Retina 3.5 Full Screen on the Simulated Metrics (right panel of the image above).

2. Search for a ScrollView object from the Objects Library (Lower-Right panel) and drag the ScrollView to the UIView (the gray rectangle above).
Leave a small space below the scrollView so that we can put the PageControl on that area.

3. Search for a PageControl object from the Objects Library (Lower-Right panel) and drag it just below our scrollView.

4. Add a <UIScrollViewDelegate> on your Interface header.
//You may put it in your .h file
@interface ViewController : UIViewController <UIScrollViewDelegate>
//OR in your .m file, directly above the @implementation header
@interface ViewController ( ) <UIScrollViewDelegate>

Read about Interface And Implementation topic to know the difference of the two.

5. Add an IBOutlet property for scrollView and pageControl in your interface.
@property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
@property (nonatomicstrongIBOutlet UIPageControl *pageControl;

And, synthesize these properties in your implementation section.
@synthesize scrollView;
@synthesize pageControl;


6. Connect your IBOutlet properties to the objects in your .xib file.

7. Right-click on your scrollView object in your .xib file. Set the delegate to the File's Owner.

8. Click the scrollView object in your .xib file and only check the Scrolling Enabled and Paging Enabled.

9. Click the pageControl object in your .xib file.
  • Set the number of Pages you want. Number of Pages == number of PageControl dots
  • Change TintColor according to your preference. 
    • Tint Color is for the normal color of the pageControl dots
    • Current Page is for the currently selected page


The rest of the tutorial will be done programmatically.

//In this tutorial, I added three images to my project, namely, image1, image2, image3.



10. Add an NSArray property to your interface (.h) and synthesize your array to your implementation (.m) file.
@property (nonatomicstrong) NSArray *imageArray; //.h
@synthesize imageArray; //.m


11. In your viewDidLoad, add these codes.
- (void)viewDidLoad
{
    [super viewDidLoad];
//Put the names of our image files in our array.
    imageArray = [[NSArray alloc] initWithObjects:@"image1.jpg", @"image2.jpg", @"image3.jpg", nil];
    
    for (int i = 0; i < [imageArray count]; i++) {
//We'll create an imageView object in every 'page' of our scrollView.
        CGRect frame;
        frame.origin.x = self.scrollView.frame.size.width * i;
        frame.origin.y = 0;
        frame.sizeself.scrollView.frame.size;
        
        UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
        imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
        [self.scrollView addSubview:imageView];
    }
//Set the content size of our scrollview according to the total width of our imageView objects.
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [imageArray count], scrollView.frame.size.height);
}

11. Implement the scrollViewDidScroll method of ScrollViewDelegate.

#pragma mark - UIScrollView Delegate
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
    // Update the page when more than 50% of the previous/next page is visible
    CGFloat pageWidth = self.scrollView.frame.size.width;
    int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    self.pageControl.currentPage = page;
}

12. Hit Run and you're done!








Monday, December 17, 2012

Table Search Display Tutorial

This is what we want to achieve in this tutorial:

A table list with a search bar on top, and when we type on the search bar, the table updates its list.

Prerequisite in learning this tutorial is a knowledge in creating table views. If you still don't know how to make table views, refer to the old tutorials.  (http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html)

1. Create a New Xcode project, choose a Single View Application template.

I'm using the latest Xcode up to date, so you may see a longer UIView in our xib file (for iPhone 5 devices). But if you want the old UIView size, you may change it by choosing Retina 3.5 Full Screen on the Simulated Metrics (right panel of the image above).

2. Look for "Search Bar and Search Display Controller" in Objects Library and drag it to our UIView.


3. Set up the table, the list of items, implementation of the delegate and datasource methods of tableview and everything else. If you have no idea how, follow this tutorial about adding UITableView. (http://iosmadesimple.blogspot.com/2012/10/adding-uitableview-tutorial.html)

4. Add this to your interface header, together with your UITableViewDataSourceUITableViewDelegate:

UISearchDisplayDelegate, UISearchBarDelegate

5. We need to add two more variables:
A boolean variable that will tell us if the user is currently searching;
and a mutable array where we can put the filtered list when the user is searching.

BOOL isSearching;

NSMutableArray *filteredList;

6. Set the boolean variable to NO, and allocate and initialize the filteredList in our viewDidLoad function:
isSearching = NO;
filteredList = [[NSMutableArray alloc] init];

7. Create a method that will add an object to our filteredList according to the string typed by the user.

- (void)filterListForSearchText:(NSString *)searchText
{
    [filteredList removeAllObjects]; //clears the array from all the string objects it might contain from the previous searches
    
    for (NSString *title in list) {
        NSRange nameRange = [title rangeOfString:searchText options:NSCaseInsensitiveSearch];
        if (nameRange.location != NSNotFound) {
            [filteredList addObject:title];
        }
    }
}


8. Implement the search display delegate methods.
#pragma mark - UISearchDisplayControllerDelegate

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
//When the user taps the search bar, this means that the controller will begin searching.
    isSearching = YES;
}

- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
//When the user taps the Cancel Button, or anywhere aside from the view.
    isSearching = NO;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterListForSearchText:searchString]; // The method we made in step 7
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    [self filterListForSearchText:[self.searchDisplayController.searchBar text]]; // The method we made in step 7
    
    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

9. Update our tableview method numOfRows: and cellForRow:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    if (isSearching) { 
        //If the user is searching, use the list in our filteredList array.
        return [filteredList count];
    } else {
        return [list count];
    }

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }
    
    // Configure the cell...
    NSString *title;
    if (isSearching && [filteredList count]) {
        //If the user is searching, use the list in our filteredList array.
        title = [filteredList objectAtIndex:indexPath.row];
    } else {
        title = [list objectAtIndex:indexPath.row];
    }
    
    cell.textLabel.text = title;
    
    return cell;
}

10. Hit Run and your search display controller is done!

Thursday, November 22, 2012

Interface and Implementation

The Interface

We are all very familiar with these lines of code, right? They are found in our .h files.

@interface  ClassA:NSObject {
           dataType variable1;
}
-(returnType)method1;
@end

The purpose of interface:

The methods and the variables inside our interface are the methods and variables that can be accessed by the other classes.

The variables we put inside our curly braces are INSTANCE variables.


@interface ClassA:NSObject {
           dataType variable1;
}


A lot of people (even me) misunderstood these variables as CLASS variables.

What are Instance Variables?

"When a number of objects are created from the same class blueprint, they each have their own distinct copies of instance variables." (Source Link)
This means that every time we instantiate a class, each of these instantiations or (alloc, in our part) will have their own set of instance variables.


What are Class Variables?

"Sometimes, you want to have variables that are common to all objects. This is accomplished with the static modifier. Fields that have the static modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class." (Source Link)
This means that a particular variable will have the same value to all the other objects that instantiated that class.


Now where will you put those methods that you want to be only accessible within the class?

The Implementation

Categories and Class Extensions

Categories are very useful in adding methods to an existing class; it allows us to EXTEND the functionalities of a class without subclassing it. For example, we have Class A. Class A has method1 and method2. I also have Class B, Class B imports Class A, but I wanted to add a method in Class A without subclassing it. So I make a Category.

//Inside Implementation file of ClassB
#import "ClassA.h"
@interface ClassA(ClassA+newMethod)  <- This is a category
-(returnType)newMethod;
@end

@implementation ClassB
//implementing method in our category 'ClassA+newMethod'
-(returnType)newMethod {
}
//other methods
@end

Now, Class Extensions (or private categories) are like anonymous categories. We add methods to our class that only that method can be accessible within the class and that these methods must be implemented in our class.

//Inside Interface file of Class A
@interface  ClassA:NSObject {
           dataType variable1;
}
-(returnType)method1;
@end

//Inside Implementation file of Class A
@interface  ClassA() <- This is a class extension
{
           dataType variable2;
}
-(returnType)privateMethod;

@implementation ClassA
-(returnType)method1 {
     [self privateMethod];
}
-(returnType)privateMethod {
}
@end

With the class extension, variable2 and privateMethod can only be used inside ClassA. As we can see from the example, method1 is calling privateMethod. Class B can never see privateMethod() even if it imported and instantiated ClassA.

So, why not use @private if we only want to hide our iVars?

We already know what an instance variable is, right? @private means that our instance variables can be accessed from an instance of the class; it protects ivars from access of an instance of any other class. As for using an anonymous category, the variables can never be accessed nor seen from another class (even if it instantiated that class).
@private does not really hide our variables (example, in Class A) from any other class, example, Class B if somewhere inside Class B's codes instantiated Class A, Class B will still be able to access the private variables using the accessor methods or through the getters and setters.



Tuesday, October 2, 2012

Navigation Controller and a Tabbar Controller in One View

If wanted to show a Navigation Controller and a Tabbar Controller in one view, should the navigation controller be inside the tabbar controller or is it the other way around? 

Most beginners happen to do this in an INappropriate manner. The answer to my first question is that the Navigation Controller should be put inside the Tabbar Controller. And the worst part for those who do not know how to do that is that they will just put a Navigation bar at the top part of the view. Don't do this, let me help you how to do it properly.

If you could still remember how we created a Tabbed Application, do it first before following the next steps. Follow this tutorial up until Step 10. (http://iosmadesimple.blogspot.com/2012/09/tabbed-application-using-interface.html)

Let's Begin!


1. Expand the Placeholders/Objects Panel, and the Tab Bar Controller. Drag a Navigation Controller Object under the TabBar Controller.

2. Since I only want two tabs for my TabBar Controller, I will make my first tab a Navigation-Based view, so I will delete one View Controller bellow the Navigation Controller object.

For Step 1 and 2.

I edited the tint of the Navigation Bar and its Navigation Title.



Hit run and it should look like this.

3. Did you follow the tutorial above and reached step 10? If so, I'll assume that you created two view controllers already (the FirstViewController and the SecondViewController). In my FirstViewController, I added a button which will be used later on in this tutorial.


4. Import the two ViewControllers, then, go back to our MainWindow.xib, change the class of the ViewController inside the Navigation Controller. So as the ViewController inside the Tabbar Controller.


5. Create another ViewController, let's name it "ThirdViewController," put a label to indicate that it's the ThirdVC.

6. Import ThirdViewController in FirstViewController Class. Create an IBAction method that will push the ThirdVC and show it.
- (IBAction)goToThirdView:(id)sender {
    ThirdViewController *thirdVC = [[ThirdViewController alloc] init];
    [self.navigationController pushViewController:thirdVC animated:YES];
}


7. Connect the IBAction to our Button in FirstViewController.xib.


8. Hit Run, and you should be able to navigate from FirstVC to the ThirdVC and still have the TabbarController.
  








Tuesday, September 25, 2012

Tabbed Application FROM Another ViewController


WHAT IF… you wanted the very first View to be an ordinary ViewController, then when you tap a button from the first View, the secondView uses a TabBarController, how do we do it? 

This is somehow related to the things we did from our previous tutorials:
http://iosmadesimple.blogspot.com/2012/09/tabbed-application-doing-it.html OR
http://iosmadesimple.blogspot.com/2012/09/tabbed-application-using-interface.html

//I'm using the latest Xcode as of this date, Xcode 4.5, you might find the views in my xib file a bit bigger in size than the usual ones.

1. I created a New Project, having "ViewController" class as my First View. Add a label and a button for this view. And it currently looks like this:

2. Create New Files, name it FirstTabViewController and SecondTabViewController, subclass of UIViewController. Add labels so as to indicate which tabVC is which.
First Tab ViewController UI

Second Tab ViewController UI

Doing it Programmatically

3. In ViewController Class, #import FirstTabVC and SecondTabVC, create a TabBarController property, synthesize it and make an IBAction method for our button.

4. Under viewDidLoad function of ViewController Class, allocate and initialize FirstTabVC and SecondTabVC and the tabBarController;

- (void)viewDidLoad {
    [super viewDidLoad];

    FirstTabViewController *firstTab = [[FirstTabViewController alloc] init];
    SecondTabViewController *secondTab = [[SecondTabViewController allocinit];
    
    firstTab.title = @"First Tab VC"; //TabTitle
    secondTab.title = @"Second Tab VC"; //TabTitle
    
    tabController = [[UITabBarController  allocinit];
    tabController.viewControllers = [[NSArray  alloc] initWithObjects:firstTab, secondTab, nil];
}

5. Add a code in IBAction that tells it that we should show the tabbed Controller. And remember to connect this IBAction to your button in your xib file.
-(IBAction)goToTabbedView:(id)sender {
    [tabController setSelectedIndex:0];
    //[self presentModalViewController:tabController animated:YES]; //deprecated in iOS 6.0; you may use this in older versions
    [self presentViewController: tabController animated:YES completion:NULL]; //you may put completion block here if there's anything you would like it to do after this task is successful
}


6. Hit Run! 

Doint it Using Interface Builder


1. Remove or comment out all your codes (the one we created above; step 4) in viewDidLoad in ViewController Class.

2. Drag a TabBarController from the Objects Library to the Placeholder/Objects Panel.
(Photo from previous posts.)

3. Add "IBOutlet" to your UITabBarController property and synthesize it; connect whatever outlets need to be connected.

4. Expand the Placeholder/Objects Panel, and the navigationController in ViewController.xib file.
(Photo from previous posts.)

5. Click the View Controllers under UITabBarController object, change their classes to FirstTabViewController and SecondTabViewController respectively.


How to go back from our very first View Controller?

1. Add a button to any of your Tab Controllers (FirstTabViewController or SecondTabViewController). Create an IBAction and connect it to the button you added.


-(IBAction)goToFirstView:(id)sender {
    [self.tabController dismissViewControllerAnimated:YES completion:NULL];
}


Hit Run!







Download Sample Project Here!

Saturday, September 22, 2012

Tabbed Application, Using Interface Builder


If you want to create a Tabbed Application programmatically, refer to this tutorial:
http://iosmadesimple.blogspot.com/2012/09/tabbed-application-doing-it.html

Let's create a Tabbed application using Interface Builder! :D

1. Create a new empty application. Make your own MainWindow.xib file, you already know how to do this. (If not, refer to this tutorial: http://iosmadesimple.blogspot.com/2012/08/creating-our-own-mainwindowxib-for.html)

2. Go to AppDelegate.h, add a UITabBarControllerDelegate
@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>

3. add a UITabBarController property.
@property (strong, nonatomic) UITabBarController *tabBarController;

4. Synthesize your tabBarController variable in AppDelegate.m.

5. Create at least 2 View Controllers, name it First and Second ViewController. Add UILabels and other stuff, to indicate that such UI belongs to either of the two ViewControllers.

6. Add "IBOutlet" to UIWindow and UITabBarController properties in AppDelegate.h
@property (strongnonatomicIBOutlet UIWindow *window;
@property (strongnonatomic IBOutlet UITabBarController *tabController;

7. Go to your MainWindow.xib, Search for Tab Bar Controller from Objects Library and drag it to Placeholder/Objects Panel. Make the necessary connections from your AppDelegate Object outlets to your objects UIWindow and UITabBarController.

8. Right-click Window object in your Interface Builder, connect the "rootViewController" outlet to UITabBarController object.



9. Go to AppDelegate.m, under application:didFinishLaunchingWithOptions function, comment out all the codes inside that function, but leave these codes behind:
[self.window makeKeyAndVisible];
return YES;

10. Hit Run!

Let's set our two view controllers that we created a while a go, the First and Second View Controller.

11. Import the First and Second VC to your AppDelegate class.

12. Expand the Placeholders/Objects Panel, and the  TabController.

13. Select one of the two view controllers inside the Tab Controller, and change its class to "FirstViewController."

Do the same thing with the other view controller, set its class to "SecondViewController."

Hit Run and you're done! 




Note

You may add an image or a tabTitle for every ViewController by following these steps:

Expand the Placeholder/Objects Panel, the TabBarController object, and the ViewControllers under it. Click the "Tab Bar Item." Go to Attributes Inspector, the fourth button, next to "Identity Inspector." Change the Title or the Image under the "Bar Item" Category.

For the images, you have to import those images to your project first. Right-click the folders on the Project Navigator, choose "Add Files to project_name," choose the images you want to import.




Monday, September 17, 2012

UIPickerView Tutorial


1. Add a New File, subclass of ViewController, to your project. In my example, the name of my class is ViewController.

2. Open ViewController.xib and drag a pickerview to your xib file.



 3. Add a UIPickerView IBOutlet to your ViewController.h file, and synthesize it to your ViewController.m.
@property (nonatomic, strong) IBOutlet UIPickerView *myPickerView; //.h
@synthesize myPickerView; //.m

4. Connect your IBOutlet property to the object in your .xib file.


5. Go back to your ViewController.h, and make your interface header look like this:
@interface ViewController : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate

6. On your viewDidLoad, set the delegate and datasource of your pickerview to self;
- (void)viewDidLoad
{
    [super viewDidLoad];
    myPickerView.delegate = self;
    myPickerView.dataSource = self;
}

7. Add an array that will hold your items for you.
If your items are constant, use NSArray, else, use NSMutableArray.
@property (nonatomicstrong) NSArray *itemsArray; //.h
@ synthesize itemsArray; //.m

8. Initialize your array.
itemsArray = [[NSArray alloc] initWithObjects:@"Item 1", @"Item 2", @"Item 3", @"Item 4", @"Item 6", nil];

9. Add these delegate and datasource methods of pickerview in your ViewController.m class:
#pragma mark - UIPickerView DataSource
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return [itemsArray count];
}

#pragma mark - UIPickerView Delegate
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 30.0;
}

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [itemsArray objectAtIndex:row];
}

//If the user chooses from the pickerview, it calls this function;
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    //Let's print in the console what the user had chosen;
    NSLog(@"Chosen item: %@", [itemsArray objectAtIndex:row]);
}

10. Done! Hit Run!





Wednesday, September 12, 2012

Tabbed Application, Doing it Programmatically


How to create a Tabbed Application without choosing Tabbed Application in creating a new project.

1. Create a new empty application. Make your own MainWindow.xib file, you already know how to do this.

2. Go to AppDelegate.h, add a UITabBarControllerDelegate
@interface AppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>

3. Add a UITabBarController property.
@property (strong, nonatomic) UITabBarController *tabBarController;

4. Synthesize your tabBarController variable in AppDelegate.m.

5. Under function application:didFinishLaunchingWithOptions, let's allocate and initialize our tabBarController.
self.tabBarController = [[UITabBarController alloc] init];

6. Create a New File, Subclass ViewController, put all the UI components you want, you may do it programmatically, or using Interface Builder. 
In my example, I created FirstViewController and SecondViewController. I only put a UILabel in each ViewController, so that I will know that the shown ViewController is from first or second ViewController. Import these ViewControllers in your AppDelegate Class.

7. Allocate and Initialize your viewControllers, this is still under application:didFinishLaunchingWithOptions function:
 UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];
    UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];

8. Set the view controllers of our tabBarController. 
self.tabBarController.viewControllers = [NSArray arrayWithObjects: viewController1viewController2nil];


Note: If you put more viewController objects in self.tabBarController.viewControllers array, tabBarController will automatically create more tabs for you. But it will limit up to five tabs only. 
If you have more ViewControllers to show, the tabBarController will automatically change the fifth tab to "More…". And when you click "More" tab, you will see a navigation-based view, and it places your other viewControllers in a table format. Upon selecting a row from the table, that's the time your viewController will be "pushed" and viewed.


9. Set the rootViewController of your window to tabBarController.
self.window.rootViewController = self.tabBarController;

10. Tab indices start at 0, tabBarController will automatically show the viewController on index 0 (of your array). But, you may choose to show a different ViewController first by:
[self.tabBarController setSelectedIndex:1];


Note

You may add an image or a tabTitle for every ViewController...

If you want to change the image or tabTitle of the firstViewController, go to FirstViewController.m, under the initialization function. add these codes.
self.title = @"First";
self.tabBarItem.image = [UIImage imageNamed:@"myImage1"]; //Example: the filename of your image is "myImage1.png"

For the images, you have to import those images to your project first. Right-click the folders on the Project Navigator, choose "Add Files to project_name," choose the images you want to import.




Blocks From one Class to Another

One popular scenario in using blocks is when you need to update your view after a web service call is finished.