Android: łączenie tekstu i obrazu na przycisku lub ImageButton

540

Próbuję mieć obraz (jako tło) na przycisku i dodawać dynamicznie, w zależności od tego, co dzieje się w czasie wykonywania, trochę tekstu nad / nad obrazem.

Jeśli korzystam ImageButton, nie mam nawet możliwości dodania tekstu. Jeśli używam Button, mogę dodać tekst, ale zdefiniować tylko obraz z android:drawableBottompodobnymi atrybutami XML, jak tutaj zdefiniowano .

Jednak te atrybuty łączą tylko tekst i obraz w wymiarach xi y, co oznacza, że ​​mogę narysować obraz wokół mojego tekstu, ale nie poniżej / pod tekstem (z osią Z zdefiniowaną jako wychodząca z wyświetlacza).

Wszelkie sugestie, jak to zrobić? Jednym z pomysłów byłoby albo rozszerzenie, Buttonalbo ImageButtonprzesłonięcie metody draw(). Ale przy obecnym poziomie wiedzy tak naprawdę nie wiem, jak to zrobić (renderowanie 2D). Może ktoś z większym doświadczeniem zna rozwiązanie lub przynajmniej kilka wskazówek na początek?

znq
źródło
skorzystaj z inteligentnego rozwiązania
9Patch
cześć @Charu ක sprawdź to, jeśli możesz stackoverflow.com/questions/42968587/...
Mohamed Rihan

Odpowiedzi:

205

Możesz wywołać setBackground()a, Buttonaby ustawić tło przycisku.

Każdy tekst pojawi się nad tłem.

Jeśli szukasz czegoś podobnego w XML, istnieje: android:backgroundatrybut, który działa w ten sam sposób.

m_vitaly
źródło
49
Jeśli wybierzesz tę trasę, nie chcesz po prostu użyć prostego rysowania jako tła. Użyj StateListDrawable (zwykle za pomocą pliku XML <selector> w res / drawable /), aby zdefiniować tła dla różnych stanów (normalny, wciśnięty, skupiony, wyłączony itp.).
CommonsWare
Zgadzam się, poszukaj tego pytania i mojej odpowiedzi: stackoverflow.com/questions/1533038/…
m_vitaly
1
Jak głupio. Jak mogłem tego nie zauważyć w dokumentacji. Dzięki za szybką odpowiedź, a także podpowiedź do <selector>. To coś, co zdecydowanie chcę wdrożyć w przyszłości.
znq
3
Obraz nie działa poprawnie w wersjach ICS 4.0+. Korzystałem z TextView z tłem.
Meh
612

Dla użytkowników, którzy chcą po prostu umieścić tło, obraz ikony i tekst w jednym Button z różnych plików: Ustaw na Buttontle, Drawable Top / Bottom / Rigth / Left i atrybuty padding .

<Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/home_btn_test"
        android:drawableTop="@drawable/home_icon_test"
        android:textColor="#FFFFFF"
        android:id="@+id/ButtonTest"
        android:paddingTop="32sp"
        android:drawablePadding="-15sp"
        android:text="this is text"></Button>

Aby uzyskać bardziej wyrafinowaną aranżację, możesz także użyć RelativeLayout(lub dowolnego innego układu) i ustawić ją jako klikalną.

Samouczek: Świetny samouczek obejmujący oba przypadki: http://izvornikod.com/Blog/tabid/82/EntryId/8/Creating-Android-button-with-image-and-text-using-relative-layout.aspx

Jeden Świat
źródło
70
Aby to zrobić programowo, użyj b.setCompoundDrawablesWithIntrinsicBound(null,R.drawable.home_icon_test,null,null)zamiast android:drawableTopi b.setPadding(0,32,0,0)zamiast android:paddingTop.
Alex Jasmin
3
Używanie układu jako przycisku jest w rzeczywistości dość elastycznym podejściem.
sstn
2
Po prostu zamień zero na 0, jeśli używasz identyfikatorów zasobów dla swoich drawables
Ran
1
Jak mogę przeskalować obraz tła, aby dopasować go do przycisku?
Alston,
@Stallman Istnieje oparte na xml i oparte na kodzie rozwiązanie do skalowania: stackoverflow.com/questions/8223936/…
OneWorld
346

Istnieje znacznie lepsze rozwiązanie tego problemu.

Wystarczy wziąć normalny Buttoni używać drawableLeft, a gravityatrybuty.

<Button
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:drawableLeft="@drawable/my_btn_icon"
  android:gravity="left|center_vertical" />

W ten sposób otrzymujesz przycisk, który wyświetla ikonę po lewej stronie przycisku i tekst po prawej stronie ikony wyśrodkowanej pionowo .

Schlingel
źródło
2
Problem występuje z tym rozwiązaniem, jeśli wybierzesz kolor tła na przycisku (co jest prawdopodobne w tym przypadku). Wtedy nie będzie graficznej odpowiedzi na kliknięcie lub wybór. Możesz napisać selektor, aby to obsłużyć, ale wtedy nie otrzymasz domyślnych kolorów telefonu.
Vanja
9
Chciałem tylko dodać, że rysowalna właściwość wypełnienia jest bardzo przydatna, jeśli zostanie użyte to rozwiązanie.
Nikola Malešević
5
Czy istnieje sposób ustawienia wysokości i szerokości ikony do rysowania w formacie xml?
penguru
18
To świetne rozwiązanie, które zostało oficjalnie zatwierdzone na stronie dla programistów Androida: developer.android.com/guide/topics/ui/controls/button.html
twaddington
3
jeżeli przycisk jest duża, a tekst jest zmienna długo, niż wygląda jak brzydkie: ikony najwyżej lewo i tekst gdzieś w środkowej
67

wprowadź opis zdjęcia tutaj

     <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:background="@drawable/home_button"
            android:drawableLeft="@android:drawable/ic_menu_edit"
            android:drawablePadding="6dp"
            android:gravity="left|center"
            android:height="60dp"
            android:padding="6dp"
            android:text="AndroidDhina"
            android:textColor="#000"
            android:textStyle="bold" />
Dhina K.
źródło
4
Proste i złe rozwiązanie. Tylko do wyrównania do lewej.
CoolMind
2
@ CoolMind Wyjaśniam tylko dla powyższego obrazu, który załączyłem .. jeśli chcesz wyrównać do prawej użyj drawableRight
Dhina k
Nie myślałem nawet o zrobieniu tego, dopóki nie przeczytałem tej odpowiedzi. To działa jak urok!
sud007
58

Wystarczy użyć LinearLayout i udawać, że to Button- ustawienie backgroundi klikalny jest kluczem:

<LinearLayout
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:drawable/btn_default"
    android:clickable="true"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="5dp"
        android:src="@drawable/image" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_margin="5dp"
        android:text="Do stuff" />
</LinearLayout>
Kieran
źródło
1
Jak dodać efekt kliknięcia?
frankish
3
Najlepsza odpowiedź, w ten sposób zarządzasz 100% wyglądu i dotyku i nie musisz przyklejać ikony do ramki.
Climbatize
francuski, dodaj android:onClickdo swojego widoku
Giora Guttsait
43

po prostu wymień

android:background="@drawable/icon"

z

android:background="@android:color/transparent"
android:drawableTop="@drawable/[your background image here]"

izz całkiem niezła sztuczka ..;)

CMA
źródło
21

Przyjąłem inne podejście niż te tutaj wymienione i działa naprawdę dobrze, więc chciałem się tym podzielić.

Używam stylu, aby utworzyć niestandardowy przycisk z obrazem po lewej i tekstem w środkowej prawej części. Wystarczy wykonać 4 „proste kroki” poniżej:

I. Utwórz 9 łatek, używając co najmniej 3 różnych plików PNG i narzędzia, które masz na: /YOUR_OWN_PATH/android-sdk-mac_x86/tools/./draw9patch. Następnie powinieneś mieć:

button_normal.9.png, button_focused.9.png i button_pressed.9.png

Następnie pobierz lub utwórz ikonę PNG 24x24.

ic_your_icon.png

Zapisz wszystko w folderze drawable / w swoim projekcie na Androida.

II. Utwórz plik XML o nazwie button_selector.xml w swoim projekcie w folderze drawable /. Stany powinny wyglądać tak:

<item android:state_pressed="true" android:drawable="@drawable/button_pressed" />
<item android:state_focused="true" android:drawable="@drawable/button_focused" />
<item android:drawable="@drawable/button_normal" />

III. Przejdź do folderu wartości / i otwórz lub utwórz plik styles.xml i utwórz następujący kod XML:

<style name="ButtonNormalText" parent="@android:style/Widget.Button">
    <item name="android:textColor" >@color/black</item>
    <item name="android:textSize" >12dip</item>
    <item name="android:textStyle" >bold</item>
    <item name="android:height" >44dip</item>
    <item name="android:background" >@drawable/button_selector</item>
    <item name="android:focusable" >true</item>
    <item name="android:clickable" >true</item>
</style>

<style name="ButtonNormalTextWithIcon" parent="ButtonNormalText">
    <item name="android:drawableLeft" >@drawable/ic_your_icon</item>
</style>

ButtonNormalTextWithIcon jest „stylem potomnym”, ponieważ rozszerza ButtonNormalText („styl nadrzędny”).

Zauważ, że zmieniając drawableLeft w stylu ButtonNormalTextWithIcon, na drawableRight, drawableTop lub drawableBottom możesz umieścić ikonę w innym miejscu względem tekstu.

IV. Przejdź do układu / folderu, w którym masz swój XML dla interfejsu użytkownika i przejdź do przycisku, w którym chcesz zastosować styl i sprawić, aby wyglądał tak:

<Button android:id="@+id/buttonSubmit" 
android:text="@string/button_submit" 
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
style="@style/ButtonNormalTextWithIcon" ></Button>

I ... voilà! Masz przycisk z obrazkiem po lewej stronie.

Dla mnie to lepszy sposób, aby to zrobić! ponieważ robiąc to w ten sposób, możesz zarządzać rozmiarem tekstu przycisku osobno od ikony, którą chcesz wyświetlić, i używać tego samego tła do rysowania dla kilku przycisków z różnymi ikonami zgodnymi ze wskazówkami interfejsu użytkownika Androida za pomocą stylów.

Możesz także utworzyć motyw dla swojej aplikacji i dodać do niego „styl nadrzędny”, aby wszystkie przyciski wyglądały tak samo, i zastosować „styl podrzędny” z ikoną tylko tam, gdzie jest to potrzebne.

Oscar Salguero
źródło
Dobra robota. Korzystałem z podejścia widoku FrameLayout z ImageView i TextView wewnątrz, ale to podejście jest ładniejsze.
pilcrowpipe
Niesamowite podejście. Zestaw SDK na Facebooku (wersja 3) ma to samo podejście do przycisku logowania
Someone Somewhere
12
 <Button android:id="@+id/imeageTextBtn" 
        android:layout_width="240dip"
        android:layout_height="wrap_content"
        android:text="Side Icon With Text Button"
        android:textSize="20sp"
        android:drawableLeft="@drawable/left_side_icon"         
        />   
Salman Khursheed Khaleeqi
źródło
11

Możesz użyć drawableTop(również drawableLeftitp.) Dla obrazu i ustawić tekst poniżej obrazu, dodającgravity left|center_vertical

<Button
            android:id="@+id/btn_video"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:background="@null"
            android:drawableTop="@drawable/videos"
            android:gravity="left|center_vertical"
            android:onClick="onClickFragment"
            android:text="Videos"
            android:textColor="@color/white" />
Kalai.G
źródło
11

Ważna aktualizacja

Nie używaj normalnego android:drawableLeftitd. ... z wektorowymi rysunkami, w przeciwnym razie nastąpi awaria w niższych wersjach API . (Zmierzyłem się z tym w aplikacji na żywo)

Do rysowania wektorowego

Jeśli używasz rysowania wektorowego, musisz

  • Czy przeprowadziłeś migrację do systemu AndroidX? jeśli nie, musisz najpierw przeprowadzić migrację do systemu AndroidX. To bardzo proste, sprawdź, co to jest Androidx i jak przeprowadzić migrację?
  • Został wydany w wersji 1.1.0-alpha01, więc wersja appcompat powinna być co najmniej 1.1.0-alpha01. Obecna najnowsza wersja to 1.1.0-alpha02, użyj najnowszych wersji dla większej niezawodności, patrz informacje o wersji - link .

    implementation 'androidx.appcompat:appcompat:1.1.0-alpha02'

  • Użyj AppCompatTextView/ AppCompatButton/AppCompatEditText

  • Zastosowanie app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompatiapp:drawableEndCompat

Do regularnego wyciągania

Jeśli nie potrzebujesz rysowania wektorowego, możesz

  • Zastosowanie android:drawableLeft, android:drawableRight, android:drawableBottom,android:drawableTop
  • Można używać zarówno regularne TextView, Buttonze EditTextalbo AppCompatzajęcia.

Można osiągnąć wyjścia jak poniżej -

wynik

Khemraj
źródło
Korzystam z xmlns:app="http://schemas.android.com/apk/res-auto"przestrzeni nazw i nie widzę tych rzeczy kompatybilnych z aplikacjami.
Dale
1
@Dale twoja przestrzeń nazw jest poprawna, zaktualizowałem swoją odpowiedź, zobacz For vector drawablepunkt ponownie.
Khemraj
@Khemraj Jak wyśrodkowujesz zarówno tekst do rysowania, jak i tekst w jednym widoku (TextView lub Button albo coś innego), jak pokazano na dołączonym obrazku?
Ambar Jain
7

Mam nadzieję, że moje rozwiązanie będzie odpowiednie dla wielu użytkowników.

Sugeruję, aby tworzyło TextView w twoim stylu. Działa dla mnie idealnie i ma wszystkie funkcje, takie jak przycisk.

Po pierwsze, stwórzmy styl przycisku, którego możesz używać wszędzie ... Tworzę button_with_hover.xml

    <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
        <shape android:shape="rectangle"  >
            <corners android:radius="3dip" />
            <stroke android:width="1dip" android:color="#8dbab3" />
            <gradient android:angle="-90" android:startColor="#48608F" android:endColor="#48608F"  />
        </shape>

        <!--#284682;-->
        <!--border-color: #223b6f;-->
    </item>
    <item android:state_focused="true">
        <shape android:shape="rectangle"  >
            <corners android:radius="3dip" />
            <stroke android:width="1dip" android:color="#284682" />
            <solid android:color="#284682"/>
        </shape>
    </item>
    <item >
        <shape android:shape="rectangle"  >
            <corners android:radius="3dip" />
            <stroke android:width="1dip" android:color="@color/ControlColors" />
            <gradient android:angle="-90" android:startColor="@color/ControlColors" android:endColor="@color/ControlColors" />
        </shape>
    </item>

</selector>

Po drugie, stwórzmy przycisk podglądu tekstu.

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="20dip"
    android:layout_gravity="right|bottom"
    android:gravity="center"
    android:padding="12dip"
    android:background="@drawable/button_with_hover"
    android:clickable="true"
    android:drawableLeft="@android:drawable/btn_star_big_off"
    android:textColor="#ffffffff"
    android:text="Golden Gate" />

I to jest wynik. Następnie nadaj niestandardowy styl dowolnym kolorom lub innym właściwościom i marginesom. Powodzenia

wprowadź opis zdjęcia tutaj

Jevgenij Kononov
źródło
Chociaż mam jeszcze przetestować kod, ponieważ podejście wydaje się być poprawne, ale nie rozumiem powodu, dla którego efekt aktywowania w aplikacji mobilnej jest najechany.
Mohammed Akhtar Zuberi
Stworzyłem efekt aktywowania dla mojej aplikacji i podczas kompilacji aplikacji potrzebowałem efektu aktywacji. Ale to zależy od ciebie :) Możesz usunąć efekt aktywowania, jeśli nie jest to konieczne.
Jevgenij Kononov
Głosowałem za odpowiedzią, ponieważ jest to bardzo dobre podejście. Chodzi mi tylko o interfejs mobilny. Jak możesz najechać?
Mohammed Akhtar Zuberi
Oo ... Rozumiem teraz ..: D Tak, masz rację. To jest niemożliwe. Ten efekt najechania służy głównie do przyciśnięcia. Po prostu niepoprawna nazwa klasy xml
Jevgenij Kononov
5

Ten kod działa dla mnie idealnie

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

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

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

</LinearLayout>
oczy
źródło
Próbowałem twojego kodu .. to działa, ale główny problem twojego kodu, jeśli masz zestaw przycisków, z różnymi rozmiarami tekstu w każdym przycisku. Twój układ zostanie przesunięty. Tak więc każda pozycja obrazu przycisku będzie w innym miejscu. Chociaż powinno być prosto w środku. Tak dzieje się z przyciskiem.
Jevgenij Kononov
0

Możesz użyć tego:

  <Button
                    android:id="@+id/reset_all"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="5dp"
                    android:layout_weight="1"
                    android:background="@drawable/btn_med"
                    android:text="Reset all"
                    android:textColor="#ffffff" />

                <Button
                    android:id="@+id/undo"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:layout_weight="1"
                    android:background="@drawable/btn_med"
                    android:text="Undo"
                    android:textColor="#ffffff" />

w tym umieściłem obraz jako backgroundi również dodałem tekst ..!

dżigar
źródło
0
<Button android:id="@+id/myButton" 
    android:layout_width="150dp"
    android:layout_height="wrap_content"
    android:text="Image Button"
    android:drawableTop="@drawable/myimage"         
    />  

Lub możesz programowo:

Drawable drawable = getResources.getDrawable(R.drawable.myimage);
drawable.setBounds(0, 0, 60, 60);
myButton.setCompoundDrawables(null, drawable, null, null);//to the Top of the Button
Kerim FIRAT
źródło
-4
    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/temp"
        />
Jayesh Prajapati
źródło
To nie jest prawidłowa odpowiedź, ponieważ widok obrazu nie obsługuje tekstu
Muhammed Fasil