Comment centrer l'icône et le texte dans un bouton Android dont la largeur est définie sur "Remplir le parent"

118

Je veux avoir un bouton Android avec l'icône + le texte centré à l'intérieur. J'utilise l'attribut drawableLeft pour définir l'image, cela fonctionne bien si le bouton a une largeur de "wrap_content"mais j'ai besoin de l'étirer à la largeur maximale, donc j'utilise la largeur "fill_parent". Cela déplace mon icône directement à gauche du bouton et je veux que l'icône et le texte soient centrés à l'intérieur du bouton.

J'ai essayé de configurer le rembourrage mais cela ne permet que de donner une valeur fixe, donc ce n'est pas ce dont j'ai besoin. J'ai besoin d'aligner l'icône + le texte au centre.

<Button 
    android:id="@+id/startTelemoteButton" 
    android:text="@string/start_telemote"
    android:drawableLeft="@drawable/start"
    android:paddingLeft="20dip"
    android:paddingRight="20dip"            
    android:width="fill_parent"
    android:heigh="wrap_content" />

Des suggestions sur la façon dont je pourrais y parvenir?

jloriente
la source
Il est possible qu'il n'y ait pas de solution facile pour cela? Dois-je essayer avec un bouton 9patch img avec l'icône là-dedans?
jloriente
Cela pourrait être une solution. Le texte du bouton va-t-il être localisé ou statique?
Octavian A. Damiean
C'est localisé. Il n'y a pas d'autre solution pour cela? J'ai réussi à le faire avec un patch 9 mais ayant des problèmes lors du changement de locale.
jloriente
Pourquoi ne pas utiliser un bouton avec TOP dessinable et y ajouter un peu de rembourrage?
Francesco
bad framework design
Muhammad Babar

Réponses:

75

android: drawableLeft garde toujours android: paddingLeft comme distance de la bordure gauche. Lorsque le bouton n'est pas défini sur android: width = "wrap_content", il sera toujours suspendu à gauche!

Avec Android 4.0 (niveau d'API 14), vous pouvez utiliser l' attribut android: drawableStart pour placer un dessinable au début du texte. La seule solution rétrocompatible que j'ai proposée consiste à utiliser un ImageSpan pour créer un texte + image spannable:

Button button = (Button) findViewById(R.id.button);
Spannable buttonLabel = new SpannableString(" Button Text");
buttonLabel.setSpan(new ImageSpan(getApplicationContext(), R.drawable.icon,      
    ImageSpan.ALIGN_BOTTOM), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
button.setText(buttonLabel);

Dans mon cas, j'avais également besoin d'ajuster l'attribut android: gravity du Button pour le faire paraître centré:

<Button
  android:id="@+id/button"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:minHeight="32dp"
  android:minWidth="150dp"
  android:gravity="center_horizontal|top" />
Rodja
la source
Agréable. La dernière ligne devrait êtrebutton.setText(buttonLabel)
AlexD
1
Unicode dispose d'un ensemble complet d'icônes de caractères compatibles avec les chaînes d'Android. Si vous pouvez en trouver une acceptable, c'est une solution simple, et elle a l'avantage supplémentaire de s'adapter à la taille du texte. Par exemple, il a une enveloppe pour une icône de courrier électronique et quelques téléphones différents pour un bouton d'appel.
GLee
1
Je ne comprends pas comment cela a fonctionné pour n'importe qui, pour moi, cela dessine 2 icônes ... un chemin vers la gauche et une directement au centre qui s'affiche en haut du texte.
Justin le
11
drawableStart ne fonctionnera pas. Voir ce fil: stackoverflow.com/questions/15350990/... Aussi, il semble que lorsque vous définissez le texte en utilisant un spannable, le style est ignoré.
Dapp
11
drawableStart ne fonctionne pas, et il a été ajouté au niveau de l'API 17 pour prendre en charge rtl
Silvia H
35

Je sais que je suis en retard pour répondre à cette question, mais cela m'a aidé:

<FrameLayout
            android:layout_width="match_parent"
            android:layout_height="35dp"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="10dp"
            android:background="@color/fb" >

            <Button
                android:id="@+id/fbLogin"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:background="@null"
                android:drawableLeft="@drawable/ic_facebook"
                android:gravity="center"
                android:minHeight="0dp"
                android:minWidth="0dp"
                android:text="FACEBOOK"
                android:textColor="@android:color/white" />
        </FrameLayout>

J'ai trouvé cette solution à partir d'ici: les difficultés de l'interface utilisateur Android: créer un bouton avec un texte et une icône centrés

entrez la description de l'image ici

Sarvan
la source
6
Le problème avec ceci est que le bouton n'a pas la largeur de la disposition du cadre.
Clive Jefferies
29

J'ai utilisé LinearLayout au lieu de Button . Le OnClickListener , que je dois utiliser fonctionne très bien aussi pour LinearLayout.

<LinearLayout
    android:id="@+id/my_button"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/selector"
    android:gravity="center"
    android:orientation="horizontal"
    android:clickable="true">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="15dp"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/icon" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Text" />

</LinearLayout>
petrnohejl
la source
29

Toutes les réponses précédentes semblent obsolètes

Vous pouvez utiliser le MaterialButtonmaintenant qui permet de régler la gravité de l'icône.

 <com.google.android.material.button.MaterialButton
        android:id="@+id/btnDownloadPdf"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:layout_margin="16dp"
        android:gravity="center"
        android:textAllCaps="true"
        app:backgroundTint="#fc0"
        app:icon="@drawable/ic_pdf"
        app:iconGravity="textStart"
        app:iconPadding="10dp"
        app:iconTint="#f00"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:text="Download Pdf" />

entrez la description de l'image ici

Pour utiliser les composants matériels, vous devrez évidemment:

Ajouter une dépendance implementation 'com.google.android.material:material:1.3.0-alpha01' (utiliser la dernière version)

Faites étendre votre thème au thème Composants matériels

<style name="AppTheme" parent="Theme.MaterialComponents.Light">
...
</style>

Si vous ne pouvez pas le faire, étendez-le à partir du thème Material Bridge

<style name="AppTheme" parent="Theme.MaterialComponents.Light.Bridge">
...
</style>
Leo Droidcoder
la source
Merci! Tu as sauvé ma journée! Fonctionne bien
Black_Zerg
9

Je l'ajuste en ajoutant un rembourrage à gauche et à droite comme suit:

<Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/btn_facebookact_like"
            android:text="@string/btn_facebookact_like"
            android:textColor="@color/black"
            android:textAllCaps="false"
            android:background="@color/white"
            android:drawableStart="@drawable/like"
            android:drawableLeft="@drawable/like"
            android:gravity="center"
            android:layout_gravity="center"
            android:paddingLeft="40dp"
            android:paddingRight="40dp"
            />
Flowra
la source
Le paddingLeft et le paddingRight m'ont aidé dans mon centrage. voter pour une solution facile.
Arrie
2
Comment gérez-vous le fait que votre largeur soit dynamique? Si vous faites pivoter votre écran, toutes vos icônes ne seront pas centrées correctement? Je suis confronté à ce problème en fait
Jacks
C'est la meilleure réponse!
Dody Rachmat Wicaksono le
8

J'ai récemment rencontré le même problème. J'ai essayé de trouver une solution moins chère, alors j'ai trouvé ça.

   <LinearLayout
        android:id="@+id/linearButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/selector_button_translucent_ab_color"
        android:clickable="true"
        android:descendantFocusability="blocksDescendants"
        android:gravity="center"
        android:orientation="horizontal" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/app_name"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:textColor="@android:color/white" />
    </LinearLayout>

Alors appelle juste OnClickListenerleLinearLayout .

J'espère que cela aide quelqu'un car cela semble être un problème très courant. :)

Ankit Popli
la source
1
C'est une bonne idée, mais une mauvaise solution. Vous pouvez obtenir la même chose avec un seul TextView en utilisant l'attribut drawableLeft. Cela vous permet d'afficher un dessin à gauche du texte.
muetzenflo
@muetzenflo yup, c'est vrai. mais lorsque vous faites correspondre le textView à la largeur du parent, votre dessinable se déplacera à l'extrême gauche même si vous centrez votre texte. s'il vous plaît laissez-moi savoir si je me trompe. et la question ne concerne que cela.
Ankit Popli
ah désolé..Je suis venu ici pour exactement ce problème et j'ai perdu ma concentration après avoir essayé trop de choses :) Je suppose que je n'ai pas vu la forêt pour les arbres. Ma faute!
muetzenflo
7

Vous pouvez utiliser un bouton personnalisé qui mesure et se dessine pour accueillir un dessin de gauche. Veuillez trouver un exemple et une utilisation ici

public class DrawableAlignedButton extends Button {

    public DrawableAlignedButton(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public DrawableAlignedButton(Context context) {
    super(context);
}

public DrawableAlignedButton(Context context, AttributeSet attrs, int style) {
    super(context, attrs, style);
}

private Drawable mLeftDrawable;

@Override
    //Overriden to work only with a left drawable.
public void setCompoundDrawablesWithIntrinsicBounds(Drawable left,
        Drawable top, Drawable right, Drawable bottom) {
    if(left == null) return;
    left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight());
    mLeftDrawable = left;
}

@Override
protected void onDraw(Canvas canvas) {
    //transform the canvas so we can draw both image and text at center.
    canvas.save();
    canvas.translate(2+mLeftDrawable.getIntrinsicWidth()/2, 0);
    super.onDraw(canvas);
    canvas.restore();
    canvas.save();
    int widthOfText = (int)getPaint().measureText(getText().toString());
    int left = (getWidth()+widthOfText)/2 - mLeftDrawable.getIntrinsicWidth() - 2;
    canvas.translate(left, (getHeight()-mLeftDrawable.getIntrinsicHeight())/2);
    mLeftDrawable.draw(canvas);
    canvas.restore();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int height = getMeasuredHeight();
    height = Math.max(height, mLeftDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom());
    setMeasuredDimension(getMeasuredWidth(), height);
}
}

Usage

<com.mypackage.DrawableAlignedButton
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:drawableLeft="@drawable/my_drawable"
        android:gravity="center"
        android:padding="7dp"
        android:text="My Text" />
Rajiv
la source
Vous pouvez inclure du code dans votre réponse, ce qui devrait être la méthode préférée (si ce n'est pas trop long), car les liens peuvent mourir avec le temps-
Lukas Knuth
2
Pas très précis mais je
suppose
Il décale un texte vers la droite, mais pas assez (une image recouvre le texte). De plus, comme les autres solutions de vue personnalisée, il n'accepte pas le texte long.
CoolMind
5

C'est ma solution que j'ai écrite il y a 3 ans. Le bouton a du texte et une icône de gauche et est dans le cadre qui est le bouton réel ici et peut être étiré par fill_parent. Je ne peux pas le tester à nouveau, mais cela fonctionnait à l'époque. Button n'a probablement pas besoin d'être utilisé et peut être remplacé par TextView mais je ne le testerai pas pour le moment et cela ne change pas trop la fonctionnalité ici.

<FrameLayout
    android:id="@+id/login_button_login"
    android:background="@drawable/apptheme_btn_default_holo_dark"
    android:layout_width="fill_parent"
    android:layout_gravity="center"
    android:layout_height="40dp">
    <Button
        android:clickable="false"
        android:drawablePadding="15dp"
        android:layout_gravity="center"
        style="@style/WhiteText.Small.Bold"
        android:drawableLeft="@drawable/lock"
        android:background="@color/transparent"
        android:text="LOGIN" />
</FrameLayout>
Renetik
la source
1
Maintenant je vois que je n'étais pas seul avec cette solution :)
Renetik
4

Je sais que cette question est un peu plus ancienne, mais peut-être que vous êtes toujours ouvert pour des conseils ou des solutions de contournement:

Créez un RelativeLayout "wrap_content" avec l'image du bouton comme arrière-plan ou le bouton lui-même comme premier élément de la mise en page. Obtenez un LinearLayout et définissez-le sur "layout_centerInParent" et "wrap_content". Ensuite, définissez votre Drawable comme Imageview. Enfin, définissez un TextView avec votre texte (paramètres régionaux).

donc fondamentalement vous avez cette structure:

RelativeLayout
  Button
    LinearLayout
      ImageView
      TextView

ou comme ça:

RelativeLayout with "android-specific" button image as background
  LinearLayout
    ImageView
    TextView

Je sais qu'avec cette solution, il y a de nombreux éléments à traiter, mais vous pouvez créer très facilement votre propre bouton personnalisé avec elle et également définir la position exacte du texte et des dessinables :)

einschnaehkeee
la source
Cette approche peut bien fonctionner. Dans mon cas, tout ce dont j'avais besoin était un RelativeLayout contenant un TextView. Le RelativeLayout a l'arrière-plan, le TextView obtient l'icône drawableLeft. Ensuite, dans le code: attachez onClickListener au RelativeLayout et findViewById pour le TextView séparément si nécessaire
Stan Kurdziel
La première structure suggérée donne l'exception «Le bouton ne peut pas être converti en ViewGroup».
Youngjae
4

Ma façon de résoudre ce problème consistait à entourer le bouton d' <View ../>éléments légers qui se redimensionnent dynamiquement. Voici quelques exemples de ce qui peut être réalisé avec ceci:

Démo par Dev-iL

Notez que la zone cliquable des boutons dans l'exemple 3 est la même que dans 2 (c'est-à-dire avec des espaces), ce qui est différent de l'exemple 4 où il n'y a pas d'espaces "non cliquables" entre les deux.

Code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 1: Button with a background color:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="20dp"
            android:paddingEnd="20dp"
            android:layout_weight="0.3"/>
        <!-- Play around with the above 3 values to modify the clickable 
             area and image alignment with respect to text -->
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 2: Button group + transparent layout + spacers:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 3: Button group + colored layout:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/darker_gray">
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>

    <TextView
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:text="Example 4 (reference): Button group + no spacers:"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/darker_gray">
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>
        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"
            android:textColor="@android:color/white"
            android:drawableLeft="@android:drawable/ic_secure"
            android:drawableStart="@android:drawable/ic_secure"
            android:background="@android:color/darker_gray"
            android:paddingStart="10dp"
            android:paddingEnd="10dp"
            android:layout_weight="1"/>   
    </LinearLayout>
</LinearLayout>
Diable
la source
2

Vous pouvez créer un widget personnalisé:

La classe Java IButton:

public class IButton extends RelativeLayout {

private RelativeLayout layout;
private ImageView image;
private TextView text;

public IButton(Context context) {
    this(context, null);
}

public IButton(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public IButton(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    LayoutInflater inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.ibutton, this, true);

    layout = (RelativeLayout) view.findViewById(R.id.btn_layout);

    image = (ImageView) view.findViewById(R.id.btn_icon);
    text = (TextView) view.findViewById(R.id.btn_text);

    if (attrs != null) {
        TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.IButtonStyle);

        Drawable drawable = attributes.getDrawable(R.styleable.IButtonStyle_button_icon);
        if(drawable != null) {
            image.setImageDrawable(drawable);
        }

        String str = attributes.getString(R.styleable.IButtonStyle_button_text);
        text.setText(str);

        attributes.recycle();
    }

}

@Override
public void setOnClickListener(final OnClickListener l) {
    super.setOnClickListener(l);
    layout.setOnClickListener(l);
}

public void setDrawable(int resId) {
    image.setImageResource(resId);
}

}

La mise en page ibutton.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/btn_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" >

<ImageView
    android:id="@+id/btn_icon"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_marginRight="2dp"
    android:layout_toLeftOf="@+id/btn_text"
    android:duplicateParentState="true" />

<TextView
    android:id="@+id/btn_text"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_centerInParent="true"
    android:duplicateParentState="true"
    android:gravity="center_vertical"
    android:textColor="#000000" />
</RelativeLayout>

Pour utiliser ce widget personnalisé:

<com.test.android.widgets.IButton
     android:id="@+id/new"
     android:layout_width="fill_parent"         
     android:layout_height="@dimen/button_height"
     ibutton:button_text="@string/btn_new"
     ibutton:button_icon="@drawable/ic_action_new" />

Vous devez fournir l'espace de noms pour les attributs personnalisés xmlns: ibutton = "http://schemas.android.com/apk/res/com.test.android.xxx" où com.test.android.xxx est le package racine de L'application.

Mettez-le simplement sous xmlns: android = "http://schemas.android.com/apk/res/android".

La dernière chose dont vous aurez besoin sont les attributs personnalisés dans le fichier attrs.xml.

Dans le fichier attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="IButtonStyle">
        <attr name="button_text" />
        <attr name="button_icon" format="integer" />
    </declare-styleable>

    <attr name="button_text" />

</resources>

Pour un meilleur positionnement, enveloppez le Button personnalisé dans un LinearLayout, si vous souhaitez éviter des problèmes potentiels avec les positionnements RelativeLayout.

Prendre plaisir!

Kirilv
la source
2

J'ai eu un problème similaire mais je voulais avoir un dessin au centre sans texte et sans mise en page enveloppée. La solution était de créer un bouton personnalisé et d'ajouter un autre dessinable en plus de GAUCHE, DROITE, HAUT, BAS. On peut facilement modifier le placement dessiné et l'avoir dans la position souhaitée par rapport au texte.

CenterDrawableButton.java

public class CenterDrawableButton extends Button {
    private Drawable mDrawableCenter;

    public CenterDrawableButton(Context context) {
        super(context);
        init(context, null);
    }

    public CenterDrawableButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public CenterDrawableButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public CenterDrawableButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }


    private void init(Context context, AttributeSet attrs){
        //if (isInEditMode()) return;
        if(attrs!=null){
            TypedArray a = context.getTheme().obtainStyledAttributes(
                    attrs, R.styleable.CenterDrawableButton, 0, 0);

            try {
                setCenterDrawable(a.getDrawable(R.styleable.CenterDrawableButton_drawableCenter));

            } finally {
                a.recycle();
            }

        }
    }

    public void setCenterDrawable(int center) {
        if(center==0){
            setCenterDrawable(null);
        }else
        setCenterDrawable(getContext().getResources().getDrawable(center));
    }
    public void setCenterDrawable(@Nullable Drawable center) {
        int[] state;
        state = getDrawableState();
        if (center != null) {
            center.setState(state);
            center.setBounds(0, 0, center.getIntrinsicWidth(), center.getIntrinsicHeight());
            center.setCallback(this);
        }
        mDrawableCenter = center;
        invalidate();
        requestLayout();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(mDrawableCenter!=null) {
            setMeasuredDimension(Math.max(getMeasuredWidth(), mDrawableCenter.getIntrinsicWidth()),
                    Math.max(getMeasuredHeight(), mDrawableCenter.getIntrinsicHeight()));
        }
    }
    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        if (mDrawableCenter != null) {
            int[] state = getDrawableState();
            mDrawableCenter.setState(state);
            mDrawableCenter.setBounds(0, 0, mDrawableCenter.getIntrinsicWidth(),
                    mDrawableCenter.getIntrinsicHeight());
        }
        invalidate();
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);

        if (mDrawableCenter != null) {
            Rect rect = mDrawableCenter.getBounds();
            canvas.save();
            canvas.translate(getWidth() / 2 - rect.right / 2, getHeight() / 2 - rect.bottom / 2);
            mDrawableCenter.draw(canvas);
            canvas.restore();
        }
    }
}

attrs.xml

<resources>
    <attr name="drawableCenter" format="reference"/>
    <declare-styleable name="CenterDrawableButton">
        <attr name="drawableCenter"/>
    </declare-styleable>
</resources>

usage

<com.virtoos.android.view.custom.CenterDrawableButton
            android:id="@id/centerDrawableButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:drawableCenter="@android:drawable/ic_menu_info_details"/>
Vilen
la source
Merci! C'est ce que je cherchais.
MistaGreen
pourriez-vous m'aider s'il vous plaît dans cette question, stackoverflow.com/questions/35912539/… , avec votre réponse, je suis très proche mais deux drawables apparaissent
Reprator
Cette solution place le dessinable au centre d'un bouton, juste au-dessus du texte centré.
CoolMind
1
<style name="captionOnly">
    <item name="android:background">@null</item>
    <item name="android:clickable">false</item>
    <item name="android:focusable">false</item>
    <item name="android:minHeight">0dp</item>
    <item name="android:minWidth">0dp</item>
</style>

<FrameLayout
   style="?android:attr/buttonStyle"
   android:layout_width="match_parent"
   android:layout_height="wrap_content" >

    <Button
       style="@style/captionOnly"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:drawableLeft="@android:drawable/ic_delete"
       android:gravity="center"
       android:text="Button Challenge" />
</FrameLayout>

Placez le FrameLayout dans LinearLayout et définissez l'orientation sur Horizontal.

Feay Jarana Manotumruksa
la source
1

Vous pouvez placer le bouton sur un LinearLayout

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/activity_login_fb_height"
        android:background="@mipmap/bg_btn_fb">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/lblLoginFb"
                android:textColor="@color/white"
                android:drawableLeft="@mipmap/icon_fb"
                android:textSize="@dimen/activity_login_fb_textSize"
                android:text="Login with Facebook"
                android:gravity="center" />
        </LinearLayout>
        <Button
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/btnLoginFb"
            android:background="@color/transparent"
            />
    </RelativeLayout>
boucher202
la source
0

Que se passe-t-il si vous essayez android: gravity = "center_horizontal"?

Ted Hopp
la source
5
Ça ne marche pas. Le texte est quelque peu centré mais le drawableLeft reste sur le côté gauche.
Peter Ajtai
0

Je pense que Android: gravity = "center" devrait fonctionner

devanshu_kaushik
la source
6
Ça ne marche pas pour moi. Il centre le texte, mais le drawableLeft reste à l'extrême gauche.
Peter Ajtai
Vous devez déclarer l'icône et le texte sous le même parent, utilisez android: gravity = "center" pour le parent
devanshu_kaushik
0

Comme suggéré par Rodja, avant la version 4.0, il n'y avait pas de moyen direct de centrer le texte avec le dessinable. Et en effet, la définition d'une valeur padding_left éloigne le dessinable de la bordure. Par conséquent, ma suggestion est que lors de l'exécution, vous calculez exactement combien de pixels de la bordure gauche votre dessinable doit être, puis passez-le en utilisant setPadding Votre calcul peut être quelque chose comme

int paddingLeft = (button.getWidth() - drawableWidth - textWidth) / 2;

La largeur de votre dessin est fixe et vous pouvez la rechercher et vous pouvez également calculer ou deviner la largeur du texte.

Enfin, vous devez multiplier la valeur de remplissage par la densité de l'écran, ce que vous pouvez faire à l'aide de DisplayMetrics

ılǝ
la source
0

public class DrawableCenterTextView étend TextView {

public DrawableCenterTextView(Context context, AttributeSet attrs,
        int defStyle) {
    super(context, attrs, defStyle);
}

public DrawableCenterTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public DrawableCenterTextView(Context context) {
    super(context);
}

@Override
protected void onDraw(Canvas canvas) {
    Drawable[] drawables = getCompoundDrawables();
    if (drawables != null) {
        Drawable drawableLeft = drawables[0];
        Drawable drawableRight = drawables[2];
        if (drawableLeft != null || drawableRight != null) {
            float textWidth = getPaint().measureText(getText().toString());
            int drawablePadding = getCompoundDrawablePadding();
            int drawableWidth = 0;
            if (drawableLeft != null)
                drawableWidth = drawableLeft.getIntrinsicWidth();
            else if (drawableRight != null) {
                drawableWidth = drawableRight.getIntrinsicWidth();
            }
            float bodyWidth = textWidth + drawableWidth + drawablePadding;
            canvas.translate((getWidth() - bodyWidth) / 2, 0);
        }
    }
    super.onDraw(canvas);
}

}

tangjun
la source
Cela n'a pas du tout fonctionné pour moi. Pouvez-vous s'il vous plaît montrer un exemple? Peut-être que je ne l'utilise pas correctement
développeur Android
0

Correctif sale.

android:paddingTop="10dp"
android:drawableTop="@drawable/ic_src"

Trouver le bon rembourrage résout le but. Cependant, pour un écran varié, utilisez un remplissage différent et placez-le dans la ressource dimens dans le dossier de valeurs respectif.

Ngudup
la source
0

Utilisez RelativeLayout (conteneur) et android: layout_centerHorizontal = "true" , mon exemple:

                <RelativeLayout
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1" >

                    <CheckBox
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:layout_centerHorizontal="true"
                        android:layout_gravity="center"
                        android:layout_marginBottom="5dp"
                        android:layout_marginLeft="10dp"
                        android:layout_marginTop="5dp"
                        android:button="@drawable/bg_fav_detail"
                        android:drawablePadding="5dp"
                        android:text=" Favorite" />
                </RelativeLayout>
vuhung3990
la source
0

Autre possibilité de conserver le thème Button.

<Button
            android:id="@+id/pf_bt_edit"
            android:layout_height="@dimen/standard_height"
            android:layout_width="match_parent"
            />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_alignBottom="@id/pf_bt_edit"
            android:layout_alignLeft="@id/pf_bt_edit"
            android:layout_alignRight="@id/pf_bt_edit"
            android:layout_alignTop="@id/pf_bt_edit"
            android:layout_margin="@dimen/margin_10"
            android:clickable="false"
            android:elevation="20dp"
            android:gravity="center"
            android:orientation="horizontal"
            >

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:adjustViewBounds="true"
                android:clickable="false"
                android:src="@drawable/ic_edit_white_48dp"/>

            <TextView
                android:id="@+id/pf_tv_edit"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="@dimen/margin_5"
                android:clickable="false"
                android:gravity="center"
                android:text="@string/pf_bt_edit"/>

        </LinearLayout>

Avec cette solution, si vous ajoutez @ color / your_color @ color / your_highlight_color dans votre thème d'activité, vous pouvez avoir le thème Matherial sur Lollipop avec ombre et ondulation, et pour la version précédente, bouton plat avec votre couleur et votre couleur de surbrillance lorsque vous appuyez dessus.

De plus, avec cette solution, la redimensionnement automatique de l'image

Résultat: Premier sur l'appareil Lollipop Deuxième: Sur l'appareil pré-sucette 3ème: Appuyez sur le bouton de l'appareil Pré-sucette

entrez la description de l'image ici

Anthone
la source
0

J'ai centré textViewavec l'icône en utilisant paddingLeftet et en alignant textView à gauche | centerVertical . et pour un petit écart entre la vue et l'icône, j'ai utilisédrawablePadding

         <Button
            android:id="@+id/have_it_main"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/textbox"
            android:drawableLeft="@drawable/have_it"
            android:drawablePadding="30dp"
            android:gravity="left|center_vertical"
            android:paddingLeft="60dp"
            android:text="Owner Contact"
            android:textColor="@android:color/white" />
Zar E Ahmer
la source
2
Cela ne fonctionnera pas sur de nombreux écrans, uniquement sur celui pour lequel a android:paddingLeftfonctionné.
soshial
0

Cela peut être un fil ancien / fermé, mais j'ai cherché partout, je n'ai pas trouvé quelque chose d'utile, jusqu'à ce que je décide de créer ma propre solution. S'il y a quelqu'un ici qui essaie de chercher une réponse, essayez celle-ci, cela pourrait vous faire gagner une minute de réflexion

          <LinearLayout
            android:id="@+id/llContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/selector"
            android:clickable="true"
            android:gravity="center"
            android:orientation="vertical"
            android:padding="10dp"
            android:textStyle="bold">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="This is a text" />

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/icon_image />


        </LinearLayout>

Étant donné que la mise en page linéaire agit comme le conteneur et celui qui a le sélecteur, lorsque vous cliquez sur la mise en page linéaire entière, elle ressemblerait à ce qu'elle devrait être. si vous voulez qu'il soit à la fois centré, utilisez l'insteaf relative. Si vous voulez qu'il soit centré horizontalement, changez l'orientation en horizontal.

Prenez note N'OUBLIEZ PAS d'ajouter android: clickable = "true" à votre conteneur principal (relatif ou linéaire) pour que l'action se déroule.

Encore une fois, cela peut être un vieux fil mais peut encore aider quelqu'un là-bas.

-cheers espère que cela aide- happycodings.

ralphgabb
la source
0

Si vous utilisez l'une des solutions de vue personnalisée , soyez prudent, car elles échouent souvent sur du texte long ou multiligne . J'ai réécrit quelques réponses, remplacé onDraw()et compris que c'était une mauvaise façon.

CoolMind
la source
0

J'ai vu des solutions pour aligner drawable au début / gauche mais rien pour drawable end / right, alors j'ai trouvé cette solution. Il utilise des rembourrages calculés dynamiquement pour aligner le dessin et le texte sur les côtés gauche et droit.

class IconButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = R.attr.buttonStyle
) : AppCompatButton(context, attrs, defStyle) {

    init {
        maxLines = 1
    }

    override fun onDraw(canvas: Canvas) {
        val buttonContentWidth = (width - paddingLeft - paddingRight).toFloat()

        val textWidth = paint.measureText(text.toString())

        val drawable = compoundDrawables[0] ?: compoundDrawables[2]
        val drawableWidth = drawable?.intrinsicWidth ?: 0
        val drawablePadding = if (textWidth > 0 && drawable != null) compoundDrawablePadding else 0
        val bodyWidth = textWidth + drawableWidth.toFloat() + drawablePadding.toFloat()

        canvas.save()

        val padding = (buttonContentWidth - bodyWidth).toInt() / 2
        val leftOrRight = if (compoundDrawables[0] != null) 1 else -1
        setPadding(leftOrRight * padding, 0, -leftOrRight * padding, 0)

        super.onDraw(canvas)
        canvas.restore()
    }
}

Il est important de définir la gravité dans votre mise en page sur "center_vertical | start" ou "center_vertical | end" selon l'endroit où vous définissez l'icône. Par exemple:

<com.stackoverflow.util.IconButton
        android:id="@+id/cancel_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:drawableStart="@drawable/cancel"
        android:drawablePadding="@dimen/padding_small"
        android:gravity="center_vertical|start"
        android:text="Cancel" />

Le seul problème avec cette implémentation est que le bouton ne peut avoir qu'une seule ligne de texte, sinon la zone du texte remplit le bouton et les remplissages seront de 0.

Siim Puniste
la source
-5

utilisez ceci android:background="@drawable/ic_play_arrow_black_24dp"

il suffit de définir l'arrière-plan sur l'icône que vous souhaitez centrer

kudzai zishumba
la source