Codementor Events

Parse Tutorial: Customizing Your Twitter/Facebook Signup/Login Views

Published Sep 08, 2015Last updated Feb 18, 2017
Parse Tutorial: Customizing Your Twitter/Facebook Signup/Login Views

All the code for Part 2 is available on github https://github.com/mattgoldspink/swift-parse-login-part2

In the previous tutorial we looked at how we can quickly add Login & Sign Up views to our app using Parse, Facebook and Twitter. In this tutorial, we’ll take what we have done and we will customize our Login and Sign Up views so they‘re branded for our Vay.K app that we created for the purpose of this tutorial.

1) Add a background image to the project

Firstly we’re going to pick a nice, high-quality background image to make people drool over their potential Vay.K’s. There are plenty of sites that offer free high-quality stock photos. I’ve gone for this one from Picjumbo.com. To import it into Xcode, first click on the Images.xcassets, then drag and drop it from Finder onto the sidebar:

I’d suggest renaming the image in XCode to make it easier to find it in the future - something like welcome_bg

2) Fix up the LaunchImage.xib

When we are launching our app, right now it has a pretty ugly splash screen. Let’s fix it up and use our new image instead. Open LaunchImage.xib, click the Copyright and VayK labels and hit delete key to remove them. Now let’s add a UIImageView and set it to be our welcome_bg. Make sure to set the Mode to Aspect Fill:

Now let’s add some constraints so that our image fills the screen. With the UIImageView selected in Interface Builder, click the middle button of the 3 at the bottom right corner of the canvas. Be sure to uncheck Constrain to margins and to set all the sides to be 0 so that the image is pinned to all 4 sides of the screen. Click Update 4 Constraints to apply the changes. Click the View button in the left bar and choose the far right of the 3 buttons to select Update Frame and change the rendering in Interface Builder to match our final Xib.

For now, I’m going to leave the image as is here, but you could always add a logo on top or customize it further (I want to keep things simple for the purpose of the tutorial).

3) Update the Welcome Screen with our image

Select the Main.storyboard in Xcode and click the View Controller in the left bar of Interface Builder. I’d recommend changing the title to Welcome View Controller so it will be easy to identify it further down the line. To do that, click the Attributes Inspector icon on the right and change the Title.

Next, let's add our UIImageView with identical constraints as the LaunchImage.xib. Make sure to set the Mode to Aspect Fill again!

4) Create a custom PFLoginViewController

Now we’ll customize the login screen. Create a new Swift file called LoginViewController in your project:

Inside here, create a new class with the following code:

class LoginViewController : PFLogInViewController {
   
    var backgroundImage : UIImageView!;
   
    override func viewDidLoad() {
        super.viewDidLoad()

        // set our custom background image
        backgroundImage = UIImageView(image: UIImage(named: "welcome_bg"))
        backgroundImage.contentMode = UIViewContentMode.ScaleAspectFill
        self.logInView!.insertSubview(backgroundImage, atIndex: 0)
    }
   
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // stretch background image to fill screen
        backgroundImage.frame = CGRectMake( 0,  0,  self.logInView!.frame.width,  self.logInView!.frame.height)
    }

}

Here, we’re adding a new UIImageView with our welcome_bg image into the logInView as the background ( insertSubView:atIndex). Once that is done, we will override viewDidLayoutSubviews so that we can make UIImageView the same size as our logInView.

Before we can see this in action, we need to update our existing ViewController to use this new LoginViewController. To do that, let's open the file and update the viewDidAppear function to create an instance of LoginViewController

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    if (PFUser.currentUser() == nil) {
        let loginViewController = LoginViewController()

Now let’s try it out!

Already this is looking pretty classy! But we still need to fix up a few things. Firstly the Parse logo is invisible against the background image, and in any case, our App is called Vay.K, so let’s remove "Parse" and add a new cool logo with a custom font.

I’ve decided to use the free open source Pacifico font from Google. To import it into the project, drag and drop the font from Finder into Xcode. Be sure to add it to check Copy items as needed and also add it to your Target. Then, open up your Info.plist, click the + button next to Information Property List at the top and type Fonts provided by application. Then, click the + next to that and you should see item 0 underneath. In the Value column we need to type our font file name. In our case it’s Pacifico.ttf

Now let’s add it to our LoginViewController. The PFLoginViewController actually has a logo view we can replace- perfect! Add the following to the viewDidLoad function:

// remove the parse Logo
let logo = UILabel()
logo.text = "Vay.K"
logo.textColor = UIColor.whiteColor()
logo.font = UIFont(name: "Pacifico", size: 70)
logo.shadowColor = UIColor.lightGrayColor()
logo.shadowOffset = CGSizeMake(2, 2)
logInView?.logo = logo

This creates a new UILabel and sets the text, color and font (using our custom font). I’ve also added a little drop shadow to help it stand out against the background image. Finally, it's time to replace the logo on the logInView. We also need to reposition the logo a little bit when the view is laid out, so in our existing viewDidLayoutSubviews add the following lines

// position logo at top with larger frame
logInView!.logo!.sizeToFit()
let logoFrame = logInView!.logo!.frame
logInView!.logo!.frame = CGRectMake(logoFrame.origin.x, logInView!.usernameField!.frame.origin.y - logoFrame.height - 16, logInView!.frame.width,  logoFrame.height)

This code first resizes our UILabel view to ensure it fits all the text in it. Then we reposition it’s frame so that it appears 16px above the usernameField. Doing the y position as a calculation like this ensures it will fit on screens of all sizes on various devices.

Run the app and take a look.

Not bad, huh? We’re starting to have a pro looking app already!

6) Customize the buttons and add some animation

Now it's time to really polish this screen! Let’s work the items from the top down.

Firstly, I want the Log In to have a green background, so in viewDidLoad add:

logInView?.logInButton?.setBackgroundImage(nil, forState: .Normal)
logInView?.logInButton?.backgroundColor = UIColor(red: 52/255, green: 191/255, blue: 73/255, alpha: 1)

Next up, the Forgot Password? link is completely lost, so again in viewDidLoad I’ll set it to white:

logInView?.passwordForgottenButton?.setTitleColor(UIColor.whiteColor(), forState: .Normal) 

Personally, I think the 3 buttons at the bottom for Facebook, Twitter and Sign Up clash with my colors and take away from the beautiful background, so I’m going to make them clear with a white outline and text. To do this, I’ll write a re-usable function to restyle them and pass them in one by one from viewDidLoad:

override func viewDidLoad() {
        ...
    // make the buttons classier
    customizeButton(logInView?.facebookButton!)
    customizeButton(logInView?.twitterButton!)
    customizeButton(logInView?.signUpButton!)
}

func customizeButton(button: UIButton!) {
    button.setBackgroundImage(nil, forState: .Normal)
    button.backgroundColor = UIColor.clearColor()
    button.layer.cornerRadius = 5
    button.layer.borderWidth = 1
    button.layer.borderColor = UIColor.whiteColor().CGColor
}

Finally I want to add a nice animation so the elements on the screen all float up from the bottom when the app is launched. For this I need to do a few things:

  1. I’ll create an array of all the UIView's I want to animate and initialize it viewDidLoad

  2. In viewDidLayoutSubviews I’m going to catch the y position all these views should have in another array called viewsFinalYPosition. In addition in this function I will change each UIView y position to be off the screen by adding it to the height of the screen.

  3. In viewDidAppear I’ll first check that have all the y positions in viewsFinalYPosition and then, using UIView.animateWithDuration:delay:options:animations:completion I’ll go through each UIView and reset it’s y position to be what we cached (note I’m removing the y position from the viewsFinalYPositio array on each iteration of the loop - this is a little trick to let me reset the array so that the next time viewDidAppear is called it won’t re-animate everything again)

class LoginViewController : PFLogInViewController {
   
    var backgroundImage : UIImageView!;
    var viewsToAnimate: [UIView!]!;
    var viewsFinalYPosition : [CGFloat]!;
   
    override func viewDidLoad() {
        super.viewDidLoad()
       
        // set our custom background image
        backgroundImage = UIImageView(image: UIImage(named: "welcome_bg"))
        backgroundImage.contentMode = UIViewContentMode.ScaleAspectFill
        logInView!.insertSubview(backgroundImage, atIndex: 0)
       
        // remove the parse Logo
        let logo = UILabel()
        logo.text = "Vay.K"
        logo.textColor = UIColor.whiteColor()
        logo.font = UIFont(name: "Pacifico", size: 70)
        logo.shadowColor = UIColor.lightGrayColor()
        logo.shadowOffset = CGSizeMake(2, 2)
        logInView?.logo = logo
       
        // set forgotten password button to white
        logInView?.passwordForgottenButton?.setTitleColor(UIColor.whiteColor(), forState: .Normal)
       
        // make the background of the login button pop more
        logInView?.logInButton?.setBackgroundImage(nil, forState: .Normal)
        logInView?.logInButton?.backgroundColor = UIColor(red: 52/255, green: 191/255, blue: 73/255, alpha: 1)
       
        // make the buttons classier
        customizeButton(logInView?.facebookButton!)
        customizeButton(logInView?.twitterButton!)
        customizeButton(logInView?.signUpButton!)
       
        // create an array of all the views we want to animate in when we launch
        // the screen
        viewsToAnimate = [self.logInView?.usernameField, self.logInView?.passwordField, self.logInView?.logInButton, self.logInView?.passwordForgottenButton, self.logInView?.facebookButton, self.logInView?.twitterButton, self.logInView?.signUpButton, self.logInView?.logo]
       
    }
   
    func customizeButton(button: UIButton!) {
        button.setBackgroundImage(nil, forState: .Normal)
        button.backgroundColor = UIColor.clearColor()
        button.layer.cornerRadius = 5
        button.layer.borderWidth = 1
        button.layer.borderColor = UIColor.whiteColor().CGColor
    }
   
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // stretch background image to fill screen
        backgroundImage.frame = CGRectMake( 0,  0,  logInView!.frame.width,  logInView!.frame.height)
       
        // position logo at top with larger frame
        logInView!.logo!.sizeToFit()
        let logoFrame = logInView!.logo!.frame
        logInView!.logo!.frame = CGRectMake(logoFrame.origin.x, logInView!.usernameField!.frame.origin.y - logoFrame.height - 16, logInView!.frame.width,  logoFrame.height)
       
        // We to position all the views off the bottom of the screen
        // and then make them rise back to where they should be
        // so we track their final position in an array
        // but change their frame so they are shifted downwards off the screen
        viewsFinalYPosition = [CGFloat]();
        for viewToAnimate in viewsToAnimate {
            let currentFrame = viewToAnimate.frame
            viewsFinalYPosition.append(currentFrame.origin.y)
            viewToAnimate.frame = CGRectMake(currentFrame.origin.x, self.view.frame.height + currentFrame.origin.y, currentFrame.width, currentFrame.height)
        }
    }
   
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
       
        // Now we'll animate all our views back into view
        // and, using the final position we stored, we'll
        // reset them to where they should be
        if viewsFinalYPosition.count == self.viewsToAnimate.count {
            UIView.animateWithDuration(1, delay: 0.0, options: .CurveEaseInOut,  animations: { () -> Void in
                for viewToAnimate in self.viewsToAnimate {
                    let currentFrame = viewToAnimate.frame
                    viewToAnimate.frame = CGRectMake(currentFrame.origin.x, self.viewsFinalYPosition.removeAtIndex(0), currentFrame.width, currentFrame.height)
                }
            }, completion: nil)
        }
    }
   
}

Let’s check out what it looks now!

6) Fix the SignUpViewController

Now the only remaining piece is customizing the PFSignUpViewController. For this we’ll follow a very similar pattern to what we did with the LoginViewController. First, let's create a new Swift file called SignUpViewController and let’s set up the background and logo in exactly the same way in viewDidLoad and viewDidLayoutSubviews

class SignUpViewController : PFSignUpViewController {
   
    var backgroundImage : UIImageView!;
    
    override func viewDidLoad() {
        super.viewDidLoad()
       
        // set our custom background image
        backgroundImage = UIImageView(image: UIImage(named: "welcome_bg"))
        backgroundImage.contentMode = UIViewContentMode.ScaleAspectFill
        signUpView!.insertSubview(backgroundImage, atIndex: 0)
       
        // remove the parse Logo
        let logo = UILabel()
        logo.text = "Vay.K"
        logo.textColor = UIColor.whiteColor()
        logo.font = UIFont(name: "Pacifico", size: 70)
        logo.shadowColor = UIColor.lightGrayColor()
        logo.shadowOffset = CGSizeMake(2, 2)
        signUpView?.logo = logo
    }
   
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // stretch background image to fill screen
        backgroundImage.frame = CGRectMake( 0,  0,  signUpView!.frame.width,  signUpView!.frame.height)
       
        // position logo at top with larger frame
        signUpView!.logo!.sizeToFit()
        let logoFrame = signUpView!.logo!.frame
        signUpView!.logo!.frame = CGRectMake(logoFrame.origin.x, signUpView!.usernameField!.frame.origin.y - logoFrame.height - 16, signUpView!.frame.width,  logoFrame.height)
    }
     
}

If you try this out, you’ll find that it still shows the old Parse Sign Up view. This is because we need to tell our app to use this new SignUpViewController when showing the Sign Up view. We can set it up in the LogInViewController.viewDidLoad

self.signUpController = SignUpViewController()

Unfortunately, Parse doesn’t propagate the value of emailAsUsername to a custom PFSignUpViewController, so we need to set that to false explicitly. I’ve decided to do it in the existing ViewController.viewDidAppear: since I’m already doing it there for the LogInViewController

loginViewController.emailAsUsername = true
loginViewController.signUpController?.emailAsUsername = true
loginViewController.signUpController?.delegate = self

Let's try running it again.

Now the default presentViewController:animated pushing up over the existing view looks strange to me. So let’s customize that. In the SignUpViewController.viewDidLoad add the following:

self.modalTransitionStyle = UIModalTransitionStyle.FlipHorizontal

While we’re here, let’s also fix up the Sign Up button to match our Log In green, so again in viewDidLoad add

signUpView?.signUpButton?.setBackgroundImage(nil, forState: .Normal)
signUpView?.signUpButton?.backgroundColor = UIColor(red: 52/255, green: 191/255, blue: 73/255, alpha: 1)

Finally, I’m not happy with the X in the top left to close the view if the user doesn’t want to sign up, so I’m going to change it to some text similar to the Forgot Password? link on the log in screen. In viewDidLoad add:

// change dismiss button to say 'Already signed up?'
signUpView?.dismissButton!.setTitle("Already signed up?", forState: .Normal)
signUpView?.dismissButton!.setImage(nil, forState: .Normal)

And we also need to position it in viewDidLayoutSubviews:

// re-layout out dismiss button to be below sign
let dismissButtonFrame = signUpView!.dismissButton!.frame
signUpView?.dismissButton!.frame = CGRectMake(0, signUpView!.signUpButton!.frame.origin.y + signUpView!.signUpButton!.frame.height + 16.0,  signUpView!.frame.width,  dismissButtonFrame.height)

Let’s try this out now:

Now it feels like a complete app! For completeness, here’s the final SignUpViewController code

class SignUpViewController : PFSignUpViewController {
   
    var backgroundImage : UIImageView!;
   
    override func viewDidLoad() {
        super.viewDidLoad()
       
        // set our custom background image
        backgroundImage = UIImageView(image: UIImage(named: "welcome_bg"))
        backgroundImage.contentMode = UIViewContentMode.ScaleAspectFill
        signUpView!.insertSubview(backgroundImage, atIndex: 0)
       
        // remove the parse Logo
        let logo = UILabel()
        logo.text = "Vay.K"
        logo.textColor = UIColor.whiteColor()
        logo.font = UIFont(name: "Pacifico", size: 70)
        logo.shadowColor = UIColor.lightGrayColor()
        logo.shadowOffset = CGSizeMake(2, 2)
        signUpView?.logo = logo
       
        // make the background of the sign up button pop more
        signUpView?.signUpButton!.setBackgroundImage(nil, forState: .Normal)
        signUpView?.signUpButton!.backgroundColor = UIColor(red: 52/255, green: 191/255, blue: 73/255, alpha: 1)
       
        // change dismiss button to say 'Already signed up?'
        signUpView?.dismissButton!.setTitle("Already signed up?", forState: .Normal)
        signUpView?.dismissButton!.setImage(nil, forState: .Normal)

        // modify the present tranisition to be a flip instead
        self.modalTransitionStyle = UIModalTransitionStyle.FlipHorizontal
    }
   
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // stretch background image to fill screen
        backgroundImage.frame = CGRectMake( 0,  0,  signUpView!.frame.width,  signUpView!.frame.height)
       
        // position logo at top with larger frame
        signUpView!.logo!.sizeToFit()
        let logoFrame = signUpView!.logo!.frame
        signUpView!.logo!.frame = CGRectMake(logoFrame.origin.x, signUpView!.usernameField!.frame.origin.y - logoFrame.height - 16, signUpView!.frame.width,  logoFrame.height)
       
        // re-layout out dismiss button to be below sign
        let dismissButtonFrame = signUpView!.dismissButton!.frame
        signUpView?.dismissButton!.frame = CGRectMake(0, signUpView!.signUpButton!.frame.origin.y + signUpView!.signUpButton!.frame.height + 16.0,  signUpView!.frame.width,  dismissButtonFrame.height)

    }
   
}

Wrapping up

And there we have it - across 2 tutorials we saw how to add a simple Log In and Sign Up flow with Parse, and how to adjust it to make it feel like a pro polished app with minimal effort. Where do we go from here? Well, Parse offers a lot more than just sign up, including a full cloud backed database for all your users data, push notifications and more! In future tutorials we’ll look at how we can flesh out the Vay.K app to be a fully fledged social network! So keep an eye out for the next episode.

If you need any help with anything found in this tutorial feel free to reach out to me on Codementor and I'd be happy to help!

All the code for Part 2 is available on github https://github.com/mattgoldspink/swift-parse-login-part2

Discover and read more posts from Matt Goldspink
get started
post comments10Replies
Jacob M Jordan
8 years ago

Hi, I am following the beginning of the tutorial to a T, but can’t get a background image to load. (it displays behind the parse login info)

Any help would be greatly appreciated!

Thanks!

Mr Euler
9 years ago

Thanks for the great tutorial, how can I position the signup and login input text field? When I rotate the screen, it is not working , any inputs will be highly appreciated.
Thanks

seanhs
9 years ago

My sign up screen does not work. Parse has accepted the information, I know this because if I tap the sign up button twice, it says the username is taken. But the app does not move forward. Could you assist?

Show more replies