Jak wyśrodkować ikonę i tekst na przycisku Androida z szerokością ustawioną na „wypełnij rodzica”

118

Chcę mieć przycisk Androida z wyśrodkowaną ikoną + tekstem. Używam atrybutu drawableLeft, aby ustawić obraz, działa to dobrze, jeśli przycisk ma szerokość, "wrap_content"ale muszę rozciągnąć do maksymalnej szerokości, więc używam szerokości "fill_parent". Spowoduje to przeniesienie mojej ikony bezpośrednio na lewo od przycisku i chcę, aby zarówno ikona, jak i tekst były wyśrodkowane wewnątrz przycisku.

Próbowałem ustawić wypełnienie, ale to pozwala tylko na podanie stałej wartości, więc nie jest to, czego potrzebuję. Muszę mieć wyrównaną ikonę + tekst na środku.

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

Jakieś sugestie, jak mogę to osiągnąć?

jloriente
źródło
Możliwe, że nie ma na to łatwego rozwiązania? Czy muszę wypróbować zdjęcie przycisku 9patch z ikoną?
jloriente
To może być rozwiązanie. Czy tekst przycisku będzie zlokalizowany czy statyczny?
Octavian A. Damiean
Jest zlokalizowane. Nie ma na to innego rozwiązania? Udało mi się to zrobić z łatką 9, ale mam problemy ze zmianą ustawień regionalnych.
jloriente,
A co powiesz na użycie guzika z wyciąganym TOPem i dodanie do niego wyściółki?
Francesco
zły projekt frameworka
Muhammad Babar

Odpowiedzi:

75

android: drawableLeft zawsze zachowuje android: paddingLeft jako odległość od lewej krawędzi. Gdy przycisk nie jest ustawiony na android: width = "wrap_content", zawsze zawiesza się po lewej stronie!

W systemie Android 4.0 (poziom API 14) możesz użyć atrybutu android: drawableStart, aby umieścić element rysunkowy na początku tekstu. Jedynym rozwiązaniem kompatybilnym wstecz, które wymyśliłem, jest użycie ImageSpan do utworzenia łączonego tekstu + obrazu:

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

W moim przypadku musiałem również dostosować atrybut android: gravity przycisku, aby wyglądał na wyśrodkowany:

<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
źródło
Miły. Ostatnią linijką powinno byćbutton.setText(buttonLabel)
AlexD
1
Unicode zawiera obszerny zestaw ikon znaków, które są zgodne z ciągami znaków w systemie Android. Jeśli możesz znaleźć akceptowalne rozwiązanie, jest to proste rozwiązanie i ma dodatkową zaletę, że będzie skalować się z rozmiarem tekstu. Na przykład ma kopertę na ikonę wiadomości e-mail i kilka różnych telefonów na przycisk połączenia.
GLee
1
Jestem zdezorientowany, jak to zadziałało dla każdego, dla mnie rysuje 2 ikony ... jedną stronę w lewo i jedną bezpośrednio w środku, która wyświetla się nad tekstem.
Justin
11
drawableStart nie zadziała. Zobacz ten wątek: stackoverflow.com/questions/15350990/ ... Wygląda na to, że kiedy ustawiasz tekst za pomocą spannable, styl jest ignorowany.
Dapp
11
drawableStart nie działa i został dodany na poziomie API 17 w celu obsługi rtl
Silvia H
35

Wiem, że spóźniłem się z odpowiedzią na to pytanie, ale to mi pomogło:

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

Znalazłem to rozwiązanie tutaj: Android UI ma problemy: tworzenie przycisku z wyśrodkowanym tekstem i ikoną

wprowadź opis obrazu tutaj

Sarvan
źródło
6
Problem z tym polega na tym, że przycisk nie ma szerokości układu ramki.
Clive Jefferies
29

Użyłem LinearLayout zamiast Button . OnClickListener , które muszę używać działa poprawnie również dla 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
źródło
29

Wszystkie poprzednie odpowiedzi wydają się być nieaktualne

Możesz użyć MaterialButtonteraz, który pozwala ustawić grawitację ikony.

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

wprowadź opis obrazu tutaj

Aby móc korzystać z komponentów materiałowych, będziesz oczywiście musiał:

Dodaj zależność implementation 'com.google.android.material:material:1.3.0-alpha01'(użyj najnowszej wersji)

Rozszerz motyw kompozycji Material Components

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

Jeśli nie możesz tego zrobić, rozszerz go z motywu Material Bridge

<style name="AppTheme" parent="Theme.MaterialComponents.Light.Bridge">
...
</style>
Leo Droidcoder
źródło
Dzięki! Uratowałeś mi dzień! Działa dobrze
Black_Zerg
9

Dostosowuję to, dodając wypełnienie po lewej i prawej stronie w następujący sposób:

<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
źródło
PaddingLeft i paddingRight pomogły mi w centrowaniu. za łatwe rozwiązanie.
Arrie
2
Jak radzisz sobie z tym, że Twoja szerokość jest dynamiczna? Jeśli obrócisz ekran, wszystkie ikony nie zostaną wyśrodkowane, prawda? W rzeczywistości mam do czynienia z tym problemem
Jacks
to najlepsza odpowiedź!
Dody Rachmat Wicaksono
8

Niedawno natknąłem się na ten sam problem. Próbowałem znaleźć tańsze rozwiązanie, więc wymyśliłem to.

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

Następnie wystarczy wywołać OnClickListenernaLinearLayout .

Mam nadzieję, że to komuś pomoże, ponieważ wydaje się to bardzo częstym problemem. :)

Ankit Popli
źródło
1
To dobry pomysł, ale złe rozwiązanie. Możesz osiągnąć to samo za pomocą tylko jednego TextView, używając atrybutu drawableLeft. Umożliwia to przeglądanie rysunków po lewej stronie tekstu.
muetzenflo
@muetzenflo tak, zgadza się. ale kiedy dopasujesz textView do szerokości nadrzędnej, twój rysowalny przesunie się do skrajnej lewej strony, nawet jeśli wyśrodkujesz tekst. daj mi znać, jeśli się mylę. a pytanie dotyczy tylko tego.
Ankit Popli
ach przepraszam… Przyszedłem tu właśnie po ten problem i straciłem koncentrację po wypróbowaniu zbyt wielu rzeczy :) Chyba nie widziałem lasu dla drzew. Moja wina!
muetzenflo
7

Możesz użyć niestandardowego przycisku, który mierzy i rysuje się, aby pomieścić lewy rysik. Proszę znaleźć przykład i wykorzystanie tutaj

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

Stosowanie

<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
źródło
Możesz zawrzeć kod w swojej odpowiedzi, który powinien być preferowany (jeśli nie jest zbyt długi), ponieważ linki mogą z czasem umrzeć -
Lukas Knuth
2
Niezbyt dokładne, ale rozumiem
Alex Semeniuk
Przesuwa tekst w prawo, ale niewystarczająco (obraz zachodzi na tekst). Ponadto, podobnie jak inne rozwiązania niestandardowego widoku, nie akceptuje poprawnie długiego tekstu.
CoolMind
5

To jest moje rozwiązanie, które napisałem 3 lata temu. Przycisk ma tekst i lewą ikonę i znajduje się w ramce, która jest tutaj rzeczywistym przyciskiem i można go rozciągnąć za pomocą fill_parent. Nie mogę tego ponownie przetestować, ale wtedy działało. Prawdopodobnie Button nie musi być używany i można go zastąpić TextView, ale nie będę go teraz testować i nie zmienia on tutaj zbytnio funkcjonalności.

<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
źródło
1
Teraz widzę, że nie byłem sam z tym rozwiązaniem :)
Renetik
4

Wiem, że to pytanie jest nieco starsze, ale być może nadal jesteś otwarty na wskazówki lub obejścia:

Utwórz RelativeLayout „wrap_content” z obrazem przycisku jako tłem lub samym przyciskiem jako pierwszym elementem układu. Pobierz LinearLayout i ustaw go na „layout_centerInParent” i „wrap_content”. Następnie ustaw swój Drawable jako Imageview. W końcu ustaw TextView z twoim tekstem (locale).

więc w zasadzie masz taką strukturę:

RelativeLayout
  Button
    LinearLayout
      ImageView
      TextView

lub tak:

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

Wiem, że przy tym rozwiązaniu jest wiele elementów, z którymi trzeba sobie poradzić, ale możesz z nim bardzo łatwo stworzyć własny niestandardowy przycisk, a także ustawić dokładną pozycję tekstu i rysunków :)

einschnaehkeee
źródło
To podejście może działać dobrze. W moim przypadku potrzebowałem tylko RelativeLayout zawierającego TextView. RelativeLayout uzyskał tło, TextView pobiera ikonę drawableLeft. Następnie w kodzie: dołącz onClickListener do RelativeLayout i znajdźViewById dla TextView oddzielnie, jeśli to konieczne
Stan Kurdziel
Pierwsza sugerowana struktura podaje wyjątek „Button nie może być rzutowany do ViewGroup”.
Youngjae
4

Mój sposób na rozwiązanie tego problemu obejmował otoczenie przycisku lekkimi <View ../>elementami, które dynamicznie zmieniają rozmiar. Poniżej znajduje się kilka przykładów tego, co można dzięki temu osiągnąć:

Demo autorstwa Dev-iL

Zwróć uwagę, że klikalny obszar przycisków w przykładzie 3 jest taki sam jak w przykładzie 2 (tj. Zawiera spacje), co różni się od przykładu 4, w którym nie ma przerw „niemożliwych do kliknięcia” pomiędzy nimi.

Kod:

<?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>
Diabeł
źródło
2

Możesz utworzyć niestandardowy widget:

Klasa IButton w języku Java:

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

}

Układ 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>

Aby korzystać z tego niestandardowego widżetu:

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

Musisz podać przestrzeń nazw dla atrybutów niestandardowych xmlns: ibutton = "http://schemas.android.com/apk/res/com.test.android.xxx", gdzie com.test.android.xxx to pakiet główny Aplikacja.

Po prostu umieść to poniżej xmlns: android = "http://schemas.android.com/apk/res/android".

Ostatnią rzeczą, której będziesz potrzebować, są atrybuty niestandardowe w attrs.xml.

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

Aby uzyskać lepsze pozycjonowanie, zawiń przycisk niestandardowy wewnątrz LinearLayout, jeśli chcesz uniknąć potencjalnych problemów z pozycjami RelativeLayout.

Cieszyć się!

kirilv
źródło
2

Miał podobny problem, ale chciał mieć środek do rysowania bez tekstu i bez zawiniętych układów. Rozwiązaniem było stworzenie niestandardowego przycisku i dodanie jeszcze jednego elementu do rysowania oprócz LEWEGO, PRAWEGO, GÓRNEGO, DOLNEGO. Można łatwo modyfikować położenie rysowalne i ustawić je w żądanym położeniu względem tekstu.

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>

stosowanie

<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
źródło
Dzięki! Właśnie tego szukałem.
MistaGreen
czy mógłbyś mi pomóc w tym pytaniu, stackoverflow.com/questions/35912539/… , z twoją odpowiedzią jestem bardzo blisko, ale pojawiają się dwa elementy do wyciągnięcia
Reprator
To rozwiązanie umieszcza rysowalny na środku przycisku, tuż nad wyśrodkowanym tekstem.
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>

Umieść FrameLayout w LinearLayout i ustaw orientację na poziomą.

Feay Jarana Manotumruksa
źródło
1

Możesz umieścić przycisk nad 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>
rzeźnik202
źródło
0

Co się stanie, jeśli wypróbujesz android: gravity = "center_horizontal"?

Ted Hopp
źródło
5
To nie działa. Tekst jest nieco wyśrodkowany, ale drawableLeft przylega do lewej strony.
Peter Ajtai
0

Myślę, że android: gravity = "center" powinien działać

devanshu_kaushik
źródło
6
Nie działa na mnie. Wyśrodkowuje tekst, ale drawableLeft pozostaje po lewej stronie.
Peter Ajtai,
Musisz zadeklarować ikonę i tekst pod tym samym rodzicem, użyj android: gravity = "center" dla rodzica
devanshu_kaushik
0

Jak sugeruje Rodja, przed wersją 4.0 nie ma bezpośredniego sposobu na wyśrodkowanie tekstu z rysunkiem. I rzeczywiście, ustawienie wartości padding_left powoduje odsunięcie elementu rysunkowego od granicy. Dlatego moja sugestia jest taka, aby w czasie działania obliczyć dokładnie ile pikseli od lewej krawędzi musi mieć twój rysowalny element, a następnie przekazać to za pomocą setPadding Twoje obliczenia mogą wyglądać mniej więcej tak

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

Szerokość twoich rysunków jest stała i możesz ją sprawdzić, a także obliczyć lub zgadnąć szerokość tekstu.

Na koniec musisz pomnożyć wartość wypełnienia przez gęstość ekranu, co możesz zrobić za pomocą DisplayMetrics

ılǝ
źródło
0

public class DrawableCenterTextView rozszerza 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
źródło
To w ogóle mi się nie udało. Czy możesz pokazać przykład? Może nie używam go poprawnie
programista Androida
0

Brudna poprawka.

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

Ustalenie właściwej wyściółki rozwiązuje cel. Jednak w przypadku zróżnicowanego ekranu użyj innego wypełnienia i umieść go w zasobie dimens w odpowiednim folderze wartości.

Ngudup
źródło
0

Użyj RelativeLayout (kontener) i androida: layout_centerHorizontal = "true" , moja próbka:

                <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
źródło
0

Inna możliwość zachowania motywu przycisku.

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

Dzięki temu rozwiązaniu, jeśli dodasz @ color / your_color @ color / your_highlight_color w swoim motywie aktywności, możesz mieć motyw Matherial na Lollipop z cieniem i falowaniem, a dla poprzedniej wersji płaski przycisk z Twoim kolorem i podświetleniem po naciśnięciu.

Ponadto dzięki temu rozwiązaniu autoresize obrazu

Wynik: Najpierw na urządzeniu Lollipop Drugie: Na urządzeniu przed Lollipop 3: Na urządzeniu Pre Lollipop naciśnij przycisk

wprowadź opis obrazu tutaj

Anthone
źródło
0

I koncentrowały textViewsię ikona użyciu paddingLefti TextView i wyrównując do lewej | centerVertical . i dla małej przerwy między widokiem a ikoną, którego użyłemdrawablePadding

         <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
źródło
2
To nie zadziała na wielu ekranach, tylko na tym, na którym android:paddingLeftzadziałało.
soshial
0

Może to być stary / zamknięty wątek, ale szukałem wszędzie, gdzie nie znalazłem nic przydatnego, dopóki nie zdecydowałem się stworzyć własnego rozwiązania. Jeśli jest tu ktoś, kto próbuje szukać odpowiedzi, spróbuj tego, może zaoszczędzić ci minuty na zastanawianiu się

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

Ponieważ układ liniowy działa jako kontener i ten, który ma selektor, po kliknięciu całego układu liniowego wyglądałby dokładnie tak, jak powinien. jeśli chcesz, aby obie strony były wyśrodkowane, użyj funkcji względnej insteaf. Jeśli chcesz, aby był wyśrodkowany w poziomie, zmień orientację na poziomą.

Zwróć uwagę NIE zapomnij dodać android: clickable = "true" do swojego głównego kontenera (względnego lub liniowego), aby akcja miała miejsce.

Znowu może to być stary wątek, ale nadal może komuś pomóc.

- szkoda, mam nadzieję, że to pomoże - zabawne zabawy.

ralphgabb
źródło
0

Jeśli używasz jednego z rozwiązań widoku niestandardowego , zachowaj ostrożność, ponieważ często zawodzą one w przypadku długiego lub wielowierszowego tekstu . Przepisałem niektóre odpowiedzi, zastąpiłem onDraw()i zrozumiałem, że to zły sposób.

CoolMind
źródło
0

Widziałem rozwiązania do wyrównywania rysunków na początku / w lewo, ale nic na koniec do rysowania / po prawej, więc wymyśliłem to rozwiązanie. Używa dynamicznie obliczanych dopełnień do wyrównywania rysunków i tekstu po lewej i prawej stronie.

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

Ważne jest, aby ustawić grawitację w swoim układzie na „center_vertical | start” lub „center_vertical | end” w zależności od tego, gdzie ustawisz ikonę. Na przykład:

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

Jedynym problemem związanym z tą implementacją jest to, że przycisk może mieć tylko jedną linię tekstu, w przeciwnym razie obszar tekstu wypełnia przycisk, a dopełnienie będzie wynosić 0.

Siim Puniste
źródło
-5

Użyj tego android:background="@drawable/ic_play_arrow_black_24dp"

po prostu ustaw tło na ikonę, którą chcesz wyśrodkować

kudzai zishumba
źródło