问题
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
回答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];
回答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];
}
}
}
回答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.
回答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];
}];
}
}];
}
回答5:
change text in the Facebook resource bundle en.lproj Localizable.strings ... i suppose it works
回答6:
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
回答7:
I think I found a much easier way to customize the text, for example, of a FBSDKLoginButton without having to create a fully customized button from scratch that contains all the login functionality. This is nice because the FBSDKLoginButton does all the work - you just have to change the text. Sorry I only know Swift...here is the code:
var fbButton = FBSDKLoginButton()
var titleText = NSAttributedString(string: "Your new button title")
fbButton.setAttributedTitle(titleText, forState: UIControlState.Normal)
Enjoy!
回答8:
The answer to your all problems, including the label after log-in pressed is very simple:
It's like OZBA answer just remove completely the UILabel (add: [loginLabel removeFromSuperview];)
This is the full working code:
- (void)setFacebookConnectButton{
self.loginView.readPermissions = @[@"public_profile", @"email", @"user_friends"];
[self.loginView setDelegate:self];
for (id obj in self.loginView.subviews)
{
if ([obj isKindOfClass:[UIButton class]])
{
UIButton * loginButton = obj;
UIImage *loginImage = [UIImage imageNamed:@"fb_connect"];
[loginButton setBackgroundImage:loginImage forState:UIControlStateNormal];
[loginButton setBackgroundImage:nil forState:UIControlStateSelected];
[loginButton setBackgroundImage:nil forState:UIControlStateHighlighted];
[loginButton setTitle:nil forState:UIControlStateSelected];
[loginButton setTitle:nil forState:UIControlStateHighlighted];
[loginButton sizeToFit];
}
if ([obj isKindOfClass:[UILabel class]])
{
UILabel * loginLabel = obj;
loginLabel.text = @"";
loginLabel.textAlignment = NSTextAlignmentCenter;
loginLabel.frame = CGRectMake(0, 0, 271, 37);
[loginLabel removeFromSuperview];
}
}
}
回答9:
Please, read the README file in Facebook SDK. You have to add the Row - FacebookBundleName in info.plist and put it a name for your bundle. Then, add a bundle to your project with this name and put into folders named "lang.lproj": for example: en.lproj - it.lproj - fr.lproj - es.lproj.... Into this folders you have to add the Localizable.strings file, then you can localize a lot of phrases, like:
"FBLV:LogOutButton" = "Log Out";
"FBLV:LogInButton" = "Log In";
"FBLV:LoggedInAs" = "Logged in as: %@";
"FBLV:LoggedInUsingFacebook" = "Logged in using Facebook";
"FBLV:LogOutAction" = "Log Out";
"FBLV:CancelAction" = "Cancel";
Hope it helps you!
回答10:
I just found an answer for the button text updating when pressing the login button. I suffered the same problem.
How about try setting the frame of the button label to CGRectMake(0,0,0,0).
I tried it and I think it worked.
Add this code to ozba's answer:
[loginLabel setFrame:CGRectMake(0, 0, 0, 0)];
Hope this helps.
回答11:
I thought about the problem, and I personally didn't really liked the accepted answer... For various reason. Everybody is free whatever solution he likes, but I decided to share my own solution.
for (UIButton *view in loginView.subviews) {
if ([view respondsToSelector:@selector(addTarget:action:forControlEvents:)]) {
[view setBackgroundImage:nil forState:UIControlStateNormal];
[view setBackgroundImage:nil forState:UIControlStateHighlighted];
}
}
I used respondsToSelector instead of isKindOfClass because the class might be custom in the future.
回答12:
Position the FB view offscreen, or with a size of 0x0. Then, set your button's action to send the message buttonPressed: to the FB view. I think this is the easiest way.
回答13:
In My case I created a good looking Button in Photoshop and simply put it on top of faceBook button. (I know that Apple doesn't advice to put view on button But iterating on the subviews doesn't look nice to me). Hard to understand why such company as FB didn't provide simple way to do it.
UIImageView *fbImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"facebookButton.png"]];
CGRect newFrame = fBButtonFrame;
newFrame.origin.x = 0; newFrame.origin.y = 0;
[fbImageView setFrame:newFrame];
[fbImageView setUserInteractionEnabled:NO];
FBLoginView *loginView = [[FBLoginView alloc] init];
[loginView setFrame:fBButtonFrame];
[loginView addSubview:fbImageView];
[self.view addSubview:loginView];
回答14:
If you refer to https://github.com/facebook/facebook-ios-sdk/blob/master/src/UI/FBLoginView.m, line 299 you'll see that the text is provided by an instance method in FBLoginView. Therefore you can change this text by deriving your own class from FBLoginView and providing your own implementation of logInText:
@interface CustomFBLoginView : FBLoginView
@end
@implementation CustomFBLoginView
-(NSString*) logInText {
return @"Some custom text";
}
@end
This is a little risky as it does depend on internal implementation details.
回答15:
Since the latest version 4.X Facebook SDK ,
The Custom Login is made easier, Use FBSDKLoginManager
回答16:
According to latest Facebook Login For iOS Version 2.3.
You can use the following code snippet to login via any any Custom UIButton.
- (void)loginWithFacebook:(id) sender {
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logInWithReadPermissions:@[@"public_profile",@"email"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
// Process error
} else if (result.isCancelled) {
// Handle cancellations
} else {
// Login Successful here
// Check for any particular permissions you asked
if ([result.grantedPermissions containsObject:@"email"]) {
// Do work
}
}
}];
}
Here is the link: https://developers.facebook.com/docs/facebook-login/ios/v2.3#login-apicalls
回答17:
Simplest Solution
let FB_LoginButton = FBSDKLoginButton()
let imgV = UIImageView(frame: FB_LoginButton.frame)
img.image = UIImage(named: "Your Image Name")
let textV = UILabel(frame: CGRect(x: 0, y: 0, width: FB_LoginButton.frame.size.width, height: 20)) // Set Frames as you need
textV.text = "Your Text"
textV.font = textV.font.fontWithSize(20)
// Swift 3
textV.font = textV.font.withSize(20)
imgV.addSubview(textV)
FB_LoginButton.addSubview(imgV)
来源:https://stackoverflow.com/questions/12280850/how-to-customize-fbloginview