How to customize FBLoginVIew?

34,706

Solution 1

The answer is to go over the FBLoginView subviews, find the button and the label and customize them.

Here is the code:

FBLoginView *loginview = 
[[FBLoginView alloc] initWithPermissions:[NSArray arrayWithObject:@"publish_actions"]];


loginview.frame = CGRectMake(4, 95, 271, 37);
for (id obj in loginview.subviews)
        {
            if ([obj isKindOfClass:[UIButton class]])
            {
                UIButton * loginButton =  obj;
                UIImage *loginImage = [UIImage imageNamed:@"YourImg.png"];
                [loginButton setBackgroundImage:loginImage forState:UIControlStateNormal];
                [loginButton setBackgroundImage:nil forState:UIControlStateSelected];
                [loginButton setBackgroundImage:nil forState:UIControlStateHighlighted];
                [loginButton sizeToFit];
            }
            if ([obj isKindOfClass:[UILabel class]])
            {
                UILabel * loginLabel =  obj;
                loginLabel.text = @"Log in to facebook";
                loginLabel.textAlignment = UITextAlignmentCenter;
                loginLabel.frame = CGRectMake(0, 0, 271, 37);
            }
        }

loginview.delegate = self;

[self.view addSubview:loginview];

Solution 2

I wanted to be FBLoginview shows as a UIBarbutton, So i have made a simple approach:

First i've added FBLoginView as a property:

@property (nonatomic, strong) FBLoginView* loginView;

And then i've added the login view outside the view:

    self.loginView = [[FBLoginView alloc] init];
    self.loginView.frame = CGRectMake(-500, -500, 0, 0);
    [self.view addSubview:self.loginView];
    self.loginView.delegate = self;

And then, i've added a standard system UIbarbuttonItem

    UIBarButtonItem* fbButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(fireFbLoginView)];
    [self.navigationItem setRightBarButtonItem:fbButton];

And then i set the bar button to fire click action of the FBLoginView ;)

-(void)fireFbLoginView{
for(id object in self.loginView.subviews){
    if([[object class] isSubclassOfClass:[UIButton class]]){
        UIButton* button = (UIButton*)object;
        [button sendActionsForControlEvents:UIControlEventTouchUpInside];
    }
  }
}

Solution 3

When I'm writing this, Facebook has already released version 3.0 of their SDK for iOS.

ozba's answer is sort of working but, from my opinion, it shouldn't be used.

  • Firstly, and most important, it's a general rule that it's bad practice to iterate through the subviews/superviews of an SDK component because the hierarchy can change between the SDK versions, causing errors that will be hard to track and, then, repair.
  • Secondly, when the button is clicked, for a second or two, it comes back to the original text.

My solution is really simple. In Facebook's downloaded folder, FacebookSDK, you have a folder named Samples. There, you must look in the SessionLoginSample. You can see that they have an ordinary Round Rect Button, which, through the ViewController that owns it, that has the FBLoginViewDelegate, it can change text depending on the FBSession state. Trust me, it's really simple.

Solution 4

Or read the documentation of Facebook to build Your Own Button:

https://developers.facebook.com/docs/ios/login-tutorial/#login-apicalls

like this:

- (void) buttonSelector
{
[FBSession openActiveSessionWithReadPermissions:@[@"basic_info"]
                                       allowLoginUI:YES
                                  completionHandler:
     ^(FBSession *session, FBSessionState state, NSError *error) {

         if (FBSession.activeSession.state == FBSessionStateOpen) {

             //To get the use
             [[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection,NSDictionary<FBGraphUser> *user, NSError *error) {
                 NSString *token = [[[FBSession activeSession] accessTokenData] accessToken];


             }];

         }
     }];

}

Solution 5

I am creating a custom FB button class in case I need to recycle it for other projects, It is still a first-version but works to change the button image depending on logged state and easily manage its size.

Some methods are for just-in-case.

As a note, you can also place the button view from the NIB file by setting its class to FBCustomLoginView and its delegate, but whatever size you set will always be reseted to FBLoginView's default size, so you must always set the specific size in code. (I don't know how to get frame's size from NSCoder to avoid this)

Code is AS-IS, you may edit it and are responsible of any bugs in it, I will edit this answer as I find any. I hope it is useful to someone.

In case you add it from NIB, you just adapt it with desired text and images, the rest works as if it was a FBLoginView:

    _facebookLoginButton.label.text = nil;
    [_facebookLoginButton setLoggedImage:  [UIImage imageNamed: @"ic_link_fb_on.png"] notLoggedImage:  [UIImage imageNamed: @"ic_link_fb_off.png"]];
    [_facebookLoginButton wrapButtonToSizeWidth: IS_IPAD ? 38 : 30 height: IS_IPAD ? 38 : 30 ];

FBCustomLoginView.h

#import <Foundation/Foundation.h>
#import <FacebookSDK/FacebookSDK.h>

@interface FBCustomLoginView : FBLoginView <FBLoginViewDelegate>

/** The button actual button */
@property (nonatomic, strong) UIButton* button;

/** The button label */
@property (nonatomic, strong) UILabel* label;

/** To a single button without label, set the same frame for the login button view and the actual button */
- (void)setWrappedButtonFrame:(CGRect)frame;

/** Wraps button to specified size, maintaining frame origin */
- (void)wrapButtonToSizeWidth: (CGFloat) width height: (CGFloat) height;

/** Sets a default background image for all states */
- (void) setBackgroundImage: (UIImage*) image selectedImage: (UIImage*) selectedImage highlightedImage: (UIImage*) highlightedImage disabledImage: (UIImage*) disabledImage;

/** Sets a default background image */
- (void) setBackgroundImage: (UIImage*) image;

/** Resizes the background image to specified size */
- (void) setBackgroundImageSizeWidth: (CGFloat) width height: (CGFloat) height;

/** Place images to manage and differentiate between logged in and out states */
- (void) setLoggedImage: (UIImage*) loggedImage notLoggedImage: (UIImage*) notLoggedImage;

@end

FBCustomLoginView.m

#import "FBCustomLoginView.h"

@interface FBCustomLoginView() {
    id<FBLoginViewDelegate> _delegate;
    UIImage* _loggedImage;
    UIImage* _notLoggedImage;
}

@end

@implementation FBCustomLoginView

@synthesize button = _button;
@synthesize label = _label;

#pragma mark - View lifecycle, superclass override
- (id)init {
    if (self = [super init]) {
        [self getReferences];
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame {
    if(self = [super initWithFrame: frame]) {
        [self getReferences];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder: aDecoder]) {
        [self getReferences];
    }
    return self;
}


- (void) getReferences {

    for (id obj in self.subviews) {
        if ([obj isKindOfClass:[UIButton class]]) {
            self.button = obj;
        }

        if ([obj isKindOfClass:[UILabel class]]) {
            self.label =  obj;
        }
    }

}

- (void)setDelegate:(id<FBLoginViewDelegate>)delegate {
    _delegate = delegate;
    [super setDelegate: self];
}


#pragma mark - FBLoginViewDelegate

- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
    if (_loggedImage) {
        [self setBackgroundImage: _loggedImage];
    }
    [_delegate loginViewShowingLoggedInUser: loginView];
}

- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
                            user:(id<FBGraphUser>)user {
    [_delegate loginViewFetchedUserInfo: loginView user: user];
}

- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView {

    if (_notLoggedImage) {
        [self setBackgroundImage: _notLoggedImage];
    }
    [_delegate loginViewShowingLoggedOutUser: loginView];
}

- (void)loginView:(FBLoginView *)loginView handleError:(NSError *)error {
    if ([_delegate respondsToSelector: @selector(loginView:handleError:)]) {
        [_delegate performSelector: @selector(loginView:handleError:) withObject: loginView withObject: error];
    }
}


#pragma mark - Custom methods

/** To a single button without label, set the same frame for the login button view and the actual button */
- (void)setWrappedButtonFrame:(CGRect)frame {
    [super setFrame: frame];

    if (_button) {
        [self setBackgroundImageSizeWidth: frame.size.width height: frame.size.height];
    }

}

/** Wraps button to specified size, maintaining frame origin */
- (void)wrapButtonToSizeWidth: (CGFloat) width height: (CGFloat) height {
    [super setFrame: CGRectMake(self.frame.origin.x, self.frame.origin.y, width, height)];
    if (_button) {
        [self setBackgroundImageSizeWidth: width height: height];
    }
}


- (void) setBackgroundImage: (UIImage*) image selectedImage: (UIImage*) selectedImage highlightedImage: (UIImage*) highlightedImage disabledImage: (UIImage*) disabledImage {

    [_button setBackgroundImage:image forState:UIControlStateNormal];
    [_button setBackgroundImage:selectedImage forState:UIControlStateSelected];
    [_button setBackgroundImage:highlightedImage forState:UIControlStateHighlighted];
    [_button setBackgroundImage:disabledImage forState:UIControlStateDisabled];
}

- (void) setBackgroundImage: (UIImage*) image {
    [self setBackgroundImage: image selectedImage:nil highlightedImage:nil disabledImage:nil];
}

- (void) setBackgroundImageSizeWidth: (CGFloat) width height: (CGFloat) height {
    _button.frame = CGRectMake(0, 0, width, height);
}

- (void) setLoggedImage: (UIImage*) loggedImage notLoggedImage: (UIImage*) notLoggedImage {
    _loggedImage = loggedImage;
    _notLoggedImage = notLoggedImage;

    [self setBackgroundImage: notLoggedImage];
}


@end
Share:
34,706
ozba
Author by

ozba

An ambitious entrepreneur, Software engineer, entrepreneur program graduate that decided to leave the High-Tech golden cage with the big salary to create my own dreams come true.

Updated on September 20, 2020

Comments

  • ozba
    ozba over 3 years

    In order to connect to facebook in my ios app i'm using FBLoginVIew from Facebook SDK for iOS.

    It shows a nice FB Login Button, but I want to use my own image and text for the login button. The problem is that I don't see anywhere how to customize that.

    I've managed to change the login button background image by overriding the images in FacebookSDKResources.bundle/FBLoginView/images, but I couldn't find where to change the login button text and position, so it's stays "Log in"...

    Solution, anyone?

    Thank you