Como centralizar o ícone e o texto em um botão do Android com a largura definida para “preencher o pai”

118

Quero ter um botão Android com ícone + texto centralizado dentro dele. Estou usando o atributo drawableLeft para definir a imagem, isso funciona bem se o botão tiver uma largura de, "wrap_content"mas eu preciso esticar para a largura máxima, então uso a largura "fill_parent". Isso move meu ícone diretamente para a esquerda do botão e quero o ícone e o texto centralizados dentro do botão.

Eu tentei configurar o preenchimento, mas isso só permite dar um valor fixo, então não é o que eu preciso. Preciso ter ícone + texto alinhados no centro.

<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" />

Alguma sugestão de como eu poderia conseguir isso?

Jloriente
fonte
É possível que não haja uma solução fácil para isso? Eu tenho que tentar com um botão 9patch img com o ícone lá?
jloriente,
Isso pode ser uma solução. O texto do botão será localizado ou estático?
Octavian A. Damiean,
Está localizado. Não existe outra solução para isso? Consegui fazer isso com um patch 9, mas tendo problemas ao alterar o local.
jloriente,
Que tal usar um botão com TOP drawable e adicionar algum preenchimento a ele?
Francesco
projeto de estrutura ruim
Muhammad Babar

Respostas:

75

android: drawableLeft está sempre mantendo android: paddingLeft como uma distância da borda esquerda. Quando o botão não está definido como android: width = "wrap_content", ele sempre ficará para a esquerda!

Com o Android 4.0 (API de nível 14), você pode usar o atributo android: drawableStart para colocar um drawable no início do texto. A única solução compatível com versões anteriores que encontrei é usar um ImageSpan para criar um Spannable de Texto + Imagem:

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);

No meu caso, também precisei ajustar o atributo android: gravity do Button para que pareça centralizado:

<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
fonte
Agradável. A última linha deve serbutton.setText(buttonLabel)
AlexD
1
Unicode tem um amplo conjunto de ícones de caracteres compatíveis com strings no Android. Se você puder encontrar um aceitável, esta é uma solução simples e tem a vantagem adicional de ser dimensionada com o tamanho do texto. Por exemplo, ele tem um envelope para um ícone de e-mail e alguns telefones diferentes para um botão de chamada.
GLee
1
Estou confuso como isso funcionou para qualquer pessoa, para mim ele desenha 2 ícones ... um para a esquerda e outro diretamente no centro, que é exibido no topo do texto.
Justin
11
drawableStart não funcionará. Veja este tópico: stackoverflow.com/questions/15350990/… Além disso, parece que quando você define o texto usando um spannable, o estilo é ignorado.
Dapp
11
drawableStart não funciona e foi adicionado na API de nível 17 para oferecer suporte a rtl
Silvia H
35

Sei que estou atrasado para responder a esta pergunta, mas isso me ajudou:

<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>

Eu encontrei esta solução aqui: dificuldade da interface do usuário do Android: criar um botão com texto e ícone centralizados

insira a descrição da imagem aqui

Sarvan
fonte
6
O problema com isso é que o botão não tem a largura do layout do quadro.
Clive Jefferies
29

Usei LinearLayout em vez de Button . O OnClickListener , que preciso usar, também funciona bem para 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
fonte
29

Todas as respostas anteriores parecem estar desatualizadas

Você pode usar o MaterialButtonagora, que permite definir a gravidade do ícone.

 <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" />

insira a descrição da imagem aqui

Para usar os componentes materiais, você obviamente precisará:

Adicionar uma dependência implementation 'com.google.android.material:material:1.3.0-alpha01'(usar a versão mais recente)

Faça seu tema estender o tema dos Componentes de materiais

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

Caso você não possa fazer isso, estenda-o do tema Material Bridge

<style name="AppTheme" parent="Theme.MaterialComponents.Light.Bridge">
...
</style>
Leo Droidcoder
fonte
Obrigado! Você salvou meu dia! Funciona bem
Black_Zerg
9

Eu o ajusto adicionando preenchimento à esquerda e à direita da seguinte maneira:

<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
fonte
O paddingLeft e o paddingRight ajudaram na minha centralização. upvoting para uma solução fácil.
Arrie
2
Como você gerencia o fato de que sua largura é dinâmica? Se você girar sua tela, todos os seus ícones não ficarão centralizados, certo? Estou enfrentando esse problema na verdade
Jacks
Esta é a melhor resposta!
Dody Rachmat Wicaksono
8

Recentemente, encontrei o mesmo problema. Tentei encontrar uma solução mais barata, então pensei nisso.

   <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>

Em seguida, basta ligar para o OnClickListeneron LinearLayout.

Espero que isso ajude alguém, pois parece um problema muito comum. :)

Ankit Popli
fonte
1
Esta é uma boa ideia, mas uma solução ruim. Você pode conseguir a mesma coisa com apenas um TextView usando o atributo drawableLeft. Isso permite que você visualize um drawable à esquerda do texto.
muetzenflo
@muetzenflo yup, isso mesmo. mas quando você faz o textView corresponder à largura do pai, seu drawable se moverá para a extrema esquerda, mesmo se você centralizar o texto. por favor, deixe-me saber se estou errado. e a questão é apenas sobre isso.
Ankit Popli
ah desculpe .. Eu vim aqui exatamente por causa desse problema e perdi o foco depois de tentar muitas coisas :) Acho que não vi a floresta por causa das árvores. Minha culpa!
muetzenflo
7

Você pode usar um botão personalizado que mede e desenha a si mesmo para acomodar um drawable esquerdo. Encontre um exemplo e uso aqui

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);
}
}

Uso

<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
fonte
Você pode incluir o código em sua resposta, que deve ser a forma preferida (se não for muito longa), pois os links podem morrer com o tempo-
Lukas Knuth
2
Não é muito preciso, mas
presumo
Ele desloca um texto para a direita, mas não o suficiente (uma imagem se sobrepõe ao texto). Além disso, como outras soluções de visualização customizada, ele não aceita texto longo direito.
CoolMind
5

Esta é a minha solução que escrevi há 3 anos. O botão tem texto e um ícone à esquerda e está no quadro que é o botão real aqui e pode ser esticado por fill_parent. Não posso testar novamente, mas estava funcionando naquela época. Provavelmente Button não precisa ser usado e pode ser substituído por TextView, mas não vou testá-lo agora e ele não muda muito a funcionalidade aqui.

<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
fonte
1
Agora vejo que não estava sozinho com esta solução :)
Renetik
4

Sei que esta pergunta é um pouco mais antiga, mas talvez você ainda esteja aberto para dicas ou soluções alternativas:

Crie um RelativeLayout "wrap_content" com a imagem do botão como plano de fundo ou o próprio botão como o primeiro elemento do layout. Obtenha um LinearLayout e defina-o como "layout_centerInParent" e "wrap_content". Em seguida, defina seu Drawable como uma visualização de imagem. Por fim, defina um TextView com seu texto (local).

então basicamente você tem esta estrutura:

RelativeLayout
  Button
    LinearLayout
      ImageView
      TextView

ou assim:

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

Eu sei que com essa solução há muitos elementos para lidar, mas você pode criar facilmente seu próprio botão personalizado com ela e também definir a posição exata do texto e dos drawables :)

einschnaehkeee
fonte
Essa abordagem pode funcionar bem. No meu caso, tudo que eu precisava era um RelativeLayout contendo um TextView. O RelativeLayout obtém o fundo, o TextView obtém o ícone drawableLeft. Em seguida, no código: anexe onClickListener ao RelativeLayout e findViewById para TextView separadamente, se necessário
Stan Kurdziel,
A primeira estrutura sugerida fornece a exceção "O botão não pode ser lançado no ViewGroup".
Youngjae
4

Minha maneira de resolver isso envolveu cercar o botão com <View ../>elementos leves que se redimensionam dinamicamente. Abaixo estão vários exemplos do que pode ser alcançado com isso:

Demo por Dev-iL

Observe que a área clicável dos botões no exemplo 3 é a mesma que no 2 (ou seja, com espaços), que é diferente do exemplo 4, onde não há lacunas "não clicáveis" entre eles.

Código:

<?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>
Diabo
fonte
2

Você pode criar um widget personalizado:

A 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);
}

}

O layout 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>

Para usar este widget personalizado:

<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" />

Você deve fornecer o namespace para os atributos personalizados xmlns: ibutton = "http://schemas.android.com/apk/res/com.test.android.xxx" onde com.test.android.xxx é o pacote raiz de a aplicação.

Basta colocá-lo abaixo de xmlns: android = "http://schemas.android.com/apk/res/android".

A última coisa de que você vai precisar são os atributos personalizados no attrs.xml.

No 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>

Para um melhor posicionamento, envolva o botão personalizado dentro de um LinearLayout, se quiser evitar possíveis problemas com os posicionamentos RelativeLayout.

Aproveitar!

Kirilv
fonte
2

Tinha um problema semelhante, mas queria um drawable central sem texto e sem layouts agrupados. A solução foi criar um botão personalizado e adicionar mais um drawable além de LEFT, RIGHT, TOP, BOTTOM. Pode-se modificar facilmente o posicionamento do drawable e colocá-lo na posição desejada em relação ao texto.

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>

uso

<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
fonte
Obrigado! É isso que eu estava procurando.
MistaGreen
Você poderia me ajudar nesta questão, stackoverflow.com/questions/35912539/… , com sua resposta estou muito perto disso, mas dois drawables aparecem
Reprator
Esta solução coloca o drawable no centro de um botão, logo acima do texto centralizado.
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>

Coloque o FrameLayout em LinearLayout e defina a orientação como Horizontal.

Feay Jarana Manotumruksa
fonte
1

Você pode colocar o botão sobre um 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>
açougueiro202
fonte
0

O que acontece se você tentar android: gravity = "center_horizontal"?

Ted Hopp
fonte
5
Não funciona. O texto está um pouco centralizado, mas o drawableLeft adere ao lado esquerdo.
Peter Ajtai
0

Acho que android: gravity = "center" deve funcionar

devanshu_kaushik
fonte
6
Não funciona para mim. Centraliza o texto, mas o drawableLeft permanece à esquerda.
Peter Ajtai
Você deve declarar o ícone e o texto sob o mesmo pai, use android: gravity = "center" para o pai
devanshu_kaushik
0

Como sugerido por Rodja, antes do 4.0 não havia uma maneira direta de centralizar o texto com o drawable. E, de fato, definir um valor de padding_left afasta o drawable da borda. Portanto, minha sugestão é que em tempo de execução você calcule exatamente quantos pixels da borda esquerda seu drawable precisa ter e depois passe-o usando setPadding Seu cálculo pode ser algo como

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

A largura do seu drawable é fixa e você pode consultá-la e também calcular ou adivinhar a largura do texto.

Finalmente, você precisaria multiplicar o valor de preenchimento pela densidade da tela, o que pode ser feito usando DisplayMetrics

ılǝ
fonte
0

public class DrawableCenterTextView extends 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
fonte
Isso não funcionou para mim em tudo. Você pode mostrar um exemplo? Talvez eu não o use corretamente
desenvolvedor do Android de
0

Correção suja.

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

Descobrir o preenchimento correto resolverá o propósito. Porém, para telas variadas, use diferentes preenchimentos e coloque esse recurso dimensional na respectiva pasta de valor.

Ngudup
fonte
0

Use RelativeLayout (container) e android: layout_centerHorizontal = "true" , meu exemplo:

                <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
fonte
0

Outra possibilidade de manter o tema do botão.

<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>

Com esta solução, se adicionar @ color / your_color @ color / your_highlight_color no seu tema de atividade, você pode ter o tema Matherial no Lollipop com sombra e ondulação e, para a versão anterior, botão plano com sua cor e cor de destaque ao pressioná-lo.

Além disso, com esta solução, o tamanho automático da imagem

Resultado: Primeiro no dispositivo Lollipop Segundo: No dispositivo pré-pirulito 3: Pressione o botão do dispositivo pré-pirulito

insira a descrição da imagem aqui

Anthone
fonte
0

Tenho centrada textViewcom o ícone usando paddingLefte e alinhando textView a esquerda | centerVertical . e para uma pequena lacuna entre a visualização e o ícone, useidrawablePadding

         <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
fonte
2
Isso não funcionará em muitas telas, apenas naquele, para o qual android:paddingLeftfuncionou.
soshial de
0

Este pode ser um tópico antigo / fechado, mas eu procurei em todos os lugares e não encontrei nada útil, até que decidi criar minha própria solução. Se houver alguém aqui tentando procurar uma resposta, experimente esta, você pode economizar um minuto para pensar

          <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>

Como o layout linear age como o contêiner e aquele que tem o seletor, quando você clica em todo o layout linear, ele fica exatamente como deveria ser. se você quiser que ambos sejam centralizados, use a folha de rosto relativa. Se você quiser centralizado horizontalmente, altere a orientação para horizontal.

Tome nota NÃO se esqueça de adicionar android: clickable = "true" ao seu contêiner principal (relativo ou linear) para que a ação ocorra.

Novamente, este pode ser um tópico antigo, mas ainda pode ajudar alguém nisso.

-cheers espero que ajude- happycodings.

Ralphgabb
fonte
0

Se você usar uma das soluções de visualização personalizada , tome cuidado, porque elas geralmente falham em texto longo ou com várias linhas . Reescrevi algumas respostas, substituí onDraw()e entendi que era um caminho errado.

CoolMind
fonte
0

Eu vi soluções para alinhar drawable em start / left, mas nada para drawable end / right, então eu vim com essa solução. Ele usa preenchimentos calculados dinamicamente para alinhar drawable e texto nos lados esquerdo e direito.

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()
    }
}

É importante definir a gravidade em seu layout para "center_vertical | start" ou "center_vertical | end", dependendo de onde você definir o ícone. Por exemplo:

<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" />

O único problema com essa implementação é que o botão pode ter apenas uma linha de texto, caso contrário, a área do texto preenche o botão e os preenchimentos serão 0.

Siim Puniste
fonte
-5

usa isto android:background="@drawable/ic_play_arrow_black_24dp"

basta definir o plano de fundo para o ícone que você deseja centralizar

Kudzai Zishumba
fonte