Facebook SDK v4的LoginButton忽略了XML自定义设置。

37
最近发布的新版Facebook SDK for Android (v4.0)导致我正在使用的自定义LoginButton表现出奇怪的行为。下面比较了在不同SDK版本中相同XML的呈现方式。

问题似乎是SDK 4.x中的FB图标不能正确地拉伸以适应自定义大小的按钮,而在4.0.1中android:layout_height属性完全被忽略

我的问题是如何使按钮在SDK 4.x中显示与在SDK 3.x中一样? XML和Java解决方案均可接受。

SDK 3.x的XML:

<com.facebook.widget.LoginButton
        android:background="@color/com_facebook_blue"
        android:id="@+id/login_btn_facebook"
        android:layout_width="225dp"
        android:layout_height="50dp"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:layout_gravity="center"
        android:onClick="onFacebookLoginClick"
            />

在SDK 3.x上的外观(在运行CM11S的OnePlus One上拍摄的屏幕截图):使用SDK v3.x运行时的XML呈现

SDK 4.x的XML(按钮包已更名+必须稍微更改宽度和字体才能匹配g+按钮):

<com.facebook.login.widget.LoginButton
        android:background="@color/com_facebook_blue"
        android:id="@+id/login_btn_facebook"
        android:layout_width="221dp"
        android:layout_height="50dp"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:layout_gravity="center"
        android:textSize="7pt"
        android:onClick="onFacebookLoginClick"
            />

如何在SDK 4.0上看起来(屏幕截图拍摄于运行未修改的4.4.4 Genymotion Nexus 5): enter image description here

如何在SDK 4.0.1上看起来(同一Genymotion Nexus 5): enter image description here

附加信息

  1. 4.0 -> 4.0.1 SDK变更日志中摘录:

登录按钮已更新以正确测量其大小。

  1. 相关帖子:

  2. 为支持不同的屏幕尺寸,在登录按钮上方我有一个ViewPagerIndicator和一个ViewPager,它被配置为在定位具有定义高度的元素后占用所有可用垂直空间。

6个回答

62

我按照以下步骤成功地获得了期望的结果:

  1. 打开了Facebook SDK 3.x LoginButton代码,并查看了那里按钮的样式如何:

    this.setBackgroundResource(R.drawable.com_facebook_button_blue);
    this.setCompoundDrawablesWithIntrinsicBounds(
                 R.drawable.com_facebook_inverse_icon, 0, 0, 0);
    this.setCompoundDrawablePadding(getResources().getDimensionPixelSize(
                 R.dimen.com_facebook_loginview_compound_drawable_padding));
    this.setPadding(getResources().getDimensionPixelSize(
                    R.dimen.com_facebook_loginview_padding_left),
                getResources().getDimensionPixelSize(
                    R.dimen.com_facebook_loginview_padding_top),
                getResources().getDimensionPixelSize(
                    R.dimen.com_facebook_loginview_padding_right),
                getResources().getDimensionPixelSize(
                    R.dimen.com_facebook_loginview_padding_bottom));
    
    根据此回答提供的解决方案,我在onPostCreate()期间更改了按钮参数,如下所示:

  2. float fbIconScale = 1.45F;
    Drawable drawable = hostActivity.getResources().getDrawable(
                                   com.facebook.R.drawable.com_facebook_button_icon);
    drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*fbIconScale),
                             (int)(drawable.getIntrinsicHeight()*fbIconScale));
    authButton.setCompoundDrawables(drawable, null, null, null); 
    authButton.setCompoundDrawablePadding(hostActivity.getResources().
                      getDimensionPixelSize(R.dimen.fb_margin_override_textpadding));
    authButton.setPadding(
            hostActivity.getResources().getDimensionPixelSize(
                                                      R.dimen.fb_margin_override_lr),
            hostActivity.getResources().getDimensionPixelSize(
                                                     R.dimen.fb_margin_override_top),
            hostActivity.getResources().getDimensionPixelSize(
                                                      R.dimen.fb_margin_override_lr),
            hostActivity.getResources().getDimensionPixelSize(
                                                 R.dimen.fb_margin_override_bottom));
    

    我的自定义维度如下:

    <dimen name="fb_margin_override_top">13dp</dimen>
    <dimen name="fb_margin_override_bottom">13dp</dimen>
    <!--The next value changes the margin between the FB icon and the left border:-->
    <dimen name="fb_margin_override_lr">10dp</dimen>
    <!--The next value changes the margin between the FB icon and the login text:-->
    <dimen name="fb_margin_override_textpadding">17dp</dimen>
    

这将导致所需的布局:

所需的布局 :D


对于Facebook SDK [4,5),图标的资源 ID 是 R.drawable.com_facebook_button_login_logo - mallaudin

12

LoginButton的高度与内边距和文本大小有关:

//LoginButton.java

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int height = (getCompoundPaddingTop() +
            (int)Math.ceil(Math.abs(fontMetrics.top) + Math.abs(fontMetrics.bottom)) +
            getCompoundPaddingBottom());
    //...
}

如果您想通过xml文件更改其高度,请使用android:padding*android:textSize属性或为其创建样式:

<style name="FacebookLoginButtonStyle">
    <item name="android:textSize">16sp</item>
    <item name="android:paddingTop">10sp</item>
    <item name="android:paddingBottom">10sp</item>
</style>

1
改变XML中的填充绝对是一个好建议,但这个答案不完整——它没有解决FB图标比例过小的问题,也没有使按钮内的文本移动(以便将其与下面的g+文本对齐)。 - Dev-iL

4
我遇到了同样的问题,我通过在Java代码中设置填充和可绘制来解决它,例如:
authButton.setPadding(0, myTopDp, 0, myBottomDp);
    authButton.setCompoundDrawablePadding(hostActivity.getResources().getDimensionPixelSize(R.dimen.fb_margin_override_textpadding));
    authButton.setCompoundDrawablesWithIntrinsicBounds(myFbResource, 0, 0, 0);

或者如果您将您的图像用作可绘制对象。
authButton.setCompoundDrawablesWithIntrinsicBounds(myFbDrawable, null, null, null);

我认为OnPostCreate方法是不必要的。

您好,感谢您的回答。我刚测试了这段代码,发现可缩放绘图貌似不起作用,而且它还卡在按钮的左边框上。哦,我的IDE似乎更喜欢使用“authButton.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);”(API 22测试时,“0”而非“null”会生成lint错误)。 - Dev-iL
嗨,方法setCompoundDrawablesWithIntrinsicBounds接受资源id或可绘制对象,在我的示例中我是指资源id(也许我需要更新我的回答)。 要缩放可绘制对象,您必须像在您的回答中那样设置填充。我会更新我的回答。 - Bronx

2
因为我想自定义登录文本gravity的起始位置,所以我遇到了setCompoundDrawablePadding方法的问题。最终我通过使用自定义布局解决了这个问题。我认为这是一种更容易自定义Facebook登录按钮的方法。
以下是最终效果: Facebook登录按钮和Google登录按钮 布局xml
<LinearLayout
        android:id="@+id/fb_login_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:background="@drawable/com_facebook_button_background"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="38dp"
            android:layout_height="38dp"
            android:layout_gravity="center_vertical"
            android:layout_marginBottom="1dp"
            android:layout_marginLeft="1dp"
            android:layout_marginStart="1dp"
            android:layout_marginTop="1dp"
            android:padding="8dp"
            android:src="@drawable/com_facebook_button_icon" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:padding="8dp"
            android:text="Log in with Facebook"
            android:textColor="@color/white"
            android:textSize="14sp"
            android:textStyle="bold" />
    </LinearLayout>

处理自定义 Facebook 登录按钮点击的 Java 代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    findViewById(R.id.fb_login_btn).setOnClickListener(this);
    boolean login = AccessToken.getCurrentAccessToken() != null;
    updateFacebookLogInButton(login);

    new AccessTokenTracker() {
        @Override
        protected void onCurrentAccessTokenChanged(
                AccessToken oldAccessToken,
                AccessToken currentAccessToken) {
            if (currentAccessToken == null) {
                updateFacebookLogInButton(false);
            }
        }
    };

    FacebookCallback<LoginResult> facebookCallback = new FacebookCallback<LoginResult>() {
        @Override
        public void onSuccess(LoginResult loginResult) {
            updateFacebookLogInButton(true);
            handleLoginResult(loginResult.getAccessToken());
        }

        @Override
        public void onCancel() {

        }

        @Override
        public void onError(FacebookException error) {
            error.printStackTrace();
        }
    };
    callbackManager = CallbackManager.Factory.create();

    loginManager = LoginManager.getInstance();
    loginManager.registerCallback(callbackManager, facebookCallback);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    callbackManager.onActivityResult(requestCode, resultCode, data);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.fb_login_btn:
            if (AccessToken.getCurrentAccessToken() == null) {
                loginManager.logInWithReadPermissions(this, Arrays.asList("public_profile", "email"));
            } else {
                String logout = getResources().getString(
                        com.facebook.R.string.com_facebook_loginview_log_out_action);
                String cancel = getResources().getString(
                        com.facebook.R.string.com_facebook_loginview_cancel_action);
                String message;
                Profile profile = Profile.getCurrentProfile();
                if (profile != null && profile.getName() != null) {
                    message = String.format(
                            getResources().getString(
                                    com.facebook.R.string.com_facebook_loginview_logged_in_as),
                            profile.getName());
                } else {
                    message = getResources().getString(
                            com.facebook.R.string.com_facebook_loginview_logged_in_using_facebook);
                }
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(message)
                        .setCancelable(true)
                        .setPositiveButton(logout, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                loginManager.logOut();
                            }
                        })
                        .setNegativeButton(cancel, null);
                builder.create().show();
            }
            break;
        default:
            break;
    }
}

private Bundle getRequestParameters() {
    Bundle parameters = new Bundle();
    parameters.putString("fields", "id,name,email,gender");
    return parameters;
}

private void updateFacebookLogInButton(boolean login) {
    TextView loginTextView = (TextView) findViewById(R.id.fb_login_tv);
    if (login) {
        loginTextView.setText("Log out");
    } else {
        loginTextView.setText("Log in with Facebook");
    }
}

private void handleRequestResult(JSONObject object) {
    // handle GraphRequest here
}

此答案目前尚不完整,因为生成的自定义布局不具备与原始FB登录按钮相同的功能(例如:与SDK进行交互并提供登录和注销功能的“onClick”行为;以及根据登录状态自动更改按钮文本)。如果您想改善答案,我建议您还提供Java代码来“恢复”丢失的功能。 - Dev-iL
谢谢@Dev-iL。我改进了答案。 - atarsdnh
谢谢。通过自定义布局和LoginManager来定制Facebook,我认为这是最好的解决方案。 - Alexei

-1
只需将按钮放入RelativeLayout中。我的高度为60dp。
 <RelativeLayout
    android:id="@+id/rlGoogle"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:layout_marginTop="30dp"
    app:layout_constraintTop_toBottomOf="@+id/btnSingInWithFace">

    <com.google.android.gms.common.SignInButton
        android:id="@+id/btnSingInWithGoogle"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

这是一个不错的提示,但这对Facebook登录按钮有效吗?毕竟,这是关于fb的问题... - Dev-iL
尝试使用以下代码添加Facebook按钮: android:paddingTop="20dp" android:paddingStart="20dp" - Miguel Vieira

-3

朋友们,你只需要设置paddingTop和paddingBottom的值。

            android:paddingTop="15dp"
            android:paddingBottom="15dp"

4
这已经被建议过了。 - Dev-iL
1
我们“人类”也知道如何阅读,不会建议已经被建议过的事情。 - rayryeng
对于我的问题来说已经足够好了:“padding”不起作用,但“paddingTop”起作用。 - Zvi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接