Jak programowo ustawić atrybut stylu w widoku


107

Otrzymuję widok z XML z poniższym kodem:

Button view = (Button) LayoutInflater.from(this).inflate(R.layout.section_button, null);

Chciałbym ustawić „styl” dla przycisku. Jak mogę to zrobić w Javie, skoro chcę użyć kilku stylów dla każdego przycisku, którego będę używał.

Odpowiedzi:


52

Generalnie nie można programowo zmieniać stylów; możesz ustawić wygląd ekranu, części układu lub pojedynczego przycisku w układzie XML za pomocą motywów lub stylów . Motywy można jednak stosować programowo .

Istnieje również coś, StateListDrawableco pozwala zdefiniować różne drawables dla każdego stanu, w którym Buttonmożesz się znajdować, niezależnie od tego, czy jest skoncentrowany, wybrany, wciśnięty, wyłączony i tak dalej.

Na przykład, aby przycisk zmieniał kolor po naciśnięciu, możesz zdefiniować plik XML o nazwie res/drawable/my_button.xmlkatalog w następujący sposób:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item
    android:state_pressed="true"
    android:drawable="@drawable/btn_pressed" />
  <item
    android:state_pressed="false"
    android:drawable="@drawable/btn_normal" />
</selector>

Następnie możesz zastosować ten selektor do a Button, ustawiając właściwość android:background="@drawable/my_button".


4
Mój problem polega na tym, że ładuję dane z usługi internetowej, które opisują informacje o moim przycisku. Przyciski muszą mieć inny styl w zależności od kategorii, do której należą. Dlatego chciałbym dynamicznie nadawać styl.
— Lint_

3
Cóż, nie możesz zmienić styleatrybutu Androida , ale możesz programowo ustawić tło w Buttontaki sam sposób, jak możesz, z dowolnym innym widokiem, jeśli to wystarczy. Ponadto, jako Buttondziedziczenie z TextView, możesz zmieniać właściwości tekstu. Wystarczy spojrzeć na dokumentację API dla tych elementów ... developer.android.com/reference/android/view/
— Christopher Orr,

Właśnie o tym myślałem, tuż przed sprawdzeniem, czy mam nowe odpowiedzi. Wielkie dzięki.
— Lint_

5
Czy nie jest możliwe utworzenie stylu dla przycisku, który definiuje rozmiar tekstu, marginesy itp., A następnie programowe zastosowanie tego do przycisku? Z pewnością można powiedzieć, czy mam sześć przycisków, które chcą mieć ten sam styl?
— Niedźwiedź

który atrybut możemy nadmuchać? czy możemy zawyżać marginesy, dopełnienie?
— Android Man

49

Po pierwsze, nie musisz używać inflatera układu, aby utworzyć prosty przycisk. Możesz po prostu użyć:

button = new Button(context);

Jeśli chcesz nadać styl przyciskowi, masz dwie możliwości: najprostsza to po prostu określenie wszystkich elementów w kodzie, jak sugeruje wiele innych odpowiedzi:

button.setTextColor(Color.RED);
button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);

Inną opcją jest zdefiniowanie stylu w XML i zastosowanie go do przycisku. W ogólnym przypadku możesz użyć ContextThemeWrapperdo tego:

ContextThemeWrapper newContext = new ContextThemeWrapper(baseContext, R.style.MyStyle);
button = new Button(newContext);

Aby zmienić atrybuty związane z tekstem w TextView (lub jego podklasach, takich jak Button), istnieje specjalna metoda:

button.setTextAppearance(context, R.style.MyTextStyle);

Ten ostatni nie może być użyty do zmiany wszystkich atrybutów; na przykład, aby zmienić dopełnienie, musisz użyć pliku ContextThemeWrapper. Ale dla koloru, rozmiaru tekstu itp. Możesz użyć setTextAppearance.


1
Po prostu genialne. ContextThemeWrapper - to jest to, czego szukałem tak długo.
— Ayaz Alifov

Działa to fantastycznie. Od jakiegoś czasu szukałem tego rozwiązania.
— jasonjwwilliams

14

Tak, możesz użyć na przykład w przycisku

Button b = new Button(this);
b.setBackgroundResource(R.drawable.selector_test);

5
To ustawi tło, ale styl może określać więcej niż tylko tło. Wygląda na to, że wiele widoków (w tym Button) ma konstruktora, który przyjmuje identyfikator stylu jako parametr. Jednak mam problemy z uruchomieniem tego dla mnie - przycisk pojawia się jako tekst bez obramowania lub czegokolwiek. Zamiast tego mógłbym utworzyć układ zawierający tylko przycisk (z określonym stylem), nadmuchać ten układ, a następnie ustawić tekst przycisku i tak dalej.
— spaaarky21

11

Możesz tworzyć atrybuty stylu, takie jak:

Button myButton = new Button(this, null,android.R.attr.buttonBarButtonStyle);

zamiast:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn"
    style="?android:attr/buttonBarButtonStyle"

    />

7
Powinna być stworzona dobra odpowiedź biorąc pod uwagę przycisk. Byłoby miło zobaczyć, jak to zrobić dla istniejącego przycisku.
— Jakość Catalyst

Zobacz odpowiedź z córek.
— Kristy Welsh

10

Jeśli korzystasz z biblioteki pomocy technicznej, możesz po prostu użyć

TextViewCompat.setTextAppearance(textView, R.style.AppTheme_TextStyle_ButtonDefault_Whatever);

dla TextViews i Buttons. Dla pozostałych widoków są podobne klasy :-)


którego pakietu R potrzebujesz, aby uzyskać ten styl?
— htafoya

6

Dla każdego, kto szuka materialnej odpowiedzi, zobacz ten wpis SO: Przyciski kolorowania w systemie Android z Material Design i AppCompat

Użyłem kombinacji tej odpowiedzi, aby ustawić domyślny kolor tekstu przycisku na biały dla mojego przycisku: https://stackoverflow.com/a/32238489/3075340

Następnie ta odpowiedź https://stackoverflow.com/a/34355919/3075340, aby programowo ustawić kolor tła. Kod do tego to:

ViewCompat.setBackgroundTintList(your_colored_button,
 ContextCompat.getColorStateList(getContext(),R.color.your_custom_color));

your_colored_buttonmoże to być zwykły Buttonprzycisk lub przycisk AppCompat, jeśli chcesz - przetestowałem powyższy kod z obydwoma typami przycisków i działa.

EDYCJA: Odkryłem, że urządzenia pre-Lollipop nie działają z powyższym kodem. Zobacz ten post, aby dowiedzieć się, jak dodać obsługę urządzeń sprzed wersji Lollipop: https://stackoverflow.com/a/30277424/3075340

Zasadniczo zrób to:

Button b = (Button) findViewById(R.id.button);
ColorStateList c = ContextCompat.getColorStateList(mContext, R.color.your_custom_color;
Drawable d = b.getBackground();
if (b instanceof AppCompatButton) {
    // appcompat button replaces tint of its drawable background
    ((AppCompatButton)b).setSupportBackgroundTintList(c);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Lollipop button replaces tint of its drawable background
    // however it is not equal to d.setTintList(c)
    b.setBackgroundTintList(c);
} else {
    // this should only happen if 
    // * manually creating a Button instead of AppCompatButton
    // * LayoutInflater did not translate a Button to AppCompatButton
    d = DrawableCompat.wrap(d);
    DrawableCompat.setTintList(d, c);
    b.setBackgroundDrawable(d);
}

6

W zależności od atrybutów stylu, które chcesz zmienić, możesz skorzystać z biblioteki Paryża:

Button view = (Button) LayoutInflater.from(this).inflate(R.layout.section_button, null);
Paris.style(view).apply(R.style.YourStyle);

Obsługiwanych jest wiele atrybutów, takich jak tło, wypełnienie, textSize, textColor itp.

Zastrzeżenie: jestem autorem biblioteki.


5

Odpowiedź udzielona przez @Dayerman i @h_rules jest właściwa. Aby podać rozbudowany przykład z kodem, w folderze do rysowania utwórz plik xml o nazwie button_disabled.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" android:padding="10dp">   
 <solid android:color="@color/silver"/>
<corners
   android:bottomRightRadius="20dp"
   android:bottomLeftRadius="20dp"
   android:topLeftRadius="20dp"
   android:topRightRadius="20dp"/>
</shape>

Następnie w Javie

((Button) findViewById(R.id.my_button)).setEnabled(false);
((Button) findViewById(R.id.my_button)).setBackgroundResource(R.drawable.button_disabled);

Spowoduje to ustawienie właściwości przycisku na wyłączone i ustawienie koloru na srebrny.

[Kolor jest zdefiniowany w color.xml jako:

<resources>

    <color name="silver">#C0C0C0</color>

</resources>

4
@Pacerier: pytanie wcale tego nie mówi. Nie jest jednoznaczne, czy styl to XML, czy java. Pyta tylko, jak programowo ustawić styl.
— Harvey

3

W czasie działania wiesz, jaki styl chcesz mieć przycisk. Tak więc wcześniej, w XML w folderze układu, możesz mieć wszystkie gotowe przyciski z potrzebnymi stylami. Więc w folderze układu możesz mieć plik o nazwie: button_style_1.xml. Zawartość tego pliku może wyglądać następująco:

<?xml version="1.0" encoding="utf-8"?>
<Button
    android:id="@+id/styleOneButton"
    style="@style/FirstStyle" />

Jeśli pracujesz z fragmentami, to w onCreateView nadmuchujesz ten przycisk, na przykład:

Button firstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);

gdzie container to kontener ViewGroup skojarzony z metodą onCreateView, którą nadpisujesz podczas tworzenia fragmentu.

Potrzebujesz jeszcze dwóch takich przycisków? Tworzysz je w ten sposób:

Button secondFirstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);
Button thirdFirstStyleBtn = (Button) inflater.inflate(R.layout.button_style_1, container, false);

Możesz dostosować te przyciski:

secondFirstStyleBtn.setText("My Second");
thirdFirstStyleBtn.setText("My Third");

Następnie dodajesz dostosowane, stylizowane przyciski do kontenera układu, który również zawyżasz w metodzie onCreateView:

_stylizedButtonsContainer = (LinearLayout) rootView.findViewById(R.id.stylizedButtonsContainer);

_stylizedButtonsContainer.addView(firstStyleBtn);
_stylizedButtonsContainer.addView(secondFirstStyleBtn);
_stylizedButtonsContainer.addView(thirdFirstStyleBtn);

I tak można dynamicznie pracować ze stylizowanymi przyciskami.


0

Zrobiłem do tego interfejs pomocniczy, używając wzoru uchwytu.

public interface StyleHolder<V extends View> {
    void applyStyle(V view);
}

Teraz dla każdego stylu, którego chcesz używać pragmatycznie, po prostu zaimplementuj interfejs, na przykład:

public class ButtonStyleHolder implements StyleHolder<Button> {

    private final Drawable background;
    private final ColorStateList textColor;
    private final int textSize;

    public ButtonStyleHolder(Context context) {
        TypedArray ta = context.obtainStyledAttributes(R.style.button, R.styleable.ButtonStyleHolder);

        Resources resources = context.getResources();

        background = ta.getDrawable(ta.getIndex(R.styleable.ButtonStyleHolder_android_background));

        textColor = ta.getColorStateList(ta.getIndex(R.styleable.ButtonStyleHolder_android_textColor));

        textSize = ta.getDimensionPixelSize(
                ta.getIndex(R.styleable.ButtonStyleHolder_android_textSize),
                resources.getDimensionPixelSize(R.dimen.standard_text_size)
        );

        // Don't forget to recycle!
        ta.recycle();
    }

    @Override
    public void applyStyle(Button btn) {
        btn.setBackground(background);
        btn.setTextColor(textColor);
        btn.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
    }
}

Zadeklaruj styl w swoim attrs.xml, stylizowany na ten przykład to:

<declare-styleable name="ButtonStyleHolder">
    <attr name="android:background" />
    <attr name="android:textSize" />
    <attr name="android:textColor" />
</declare-styleable>

Oto styl zadeklarowany w styles.xml:

<style name="button">
    <item name="android:background">@drawable/button</item>
    <item name="android:textColor">@color/light_text_color</item>
    <item name="android:textSize">@dimen/standard_text_size</item>
</style>

I wreszcie implementacja posiadacza stylu:

Button btn = new Button(context);    
StyleHolder<Button> styleHolder = new ButtonStyleHolder(context);
styleHolder.applyStyle(btn);

Uważam, że jest to bardzo pomocne, ponieważ można go łatwo ponownie wykorzystać i zachowuje kod czysty i rozwlekły, zalecałbym używanie tego tylko jako zmiennej lokalnej, abyśmy mogli pozwolić odśmiecaczowi pamięci wykonać swoją pracę, gdy skończymy ustawiać wszystkie style .


-1

Ostatnio miałem ten sam problem. oto jak to rozwiązałem.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <!-- This is the special two colors background START , after this LinearLayout, you can add all view that have it for main background-->
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:weightSum="2"

    android:background="#FFFFFF"
    android:orientation="horizontal"
    >

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#0000FF" />

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#F000F0" />
    </LinearLayout>
    <!-- This is the special two colors background END-->

   <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:text="This Text is centered with a special backgound,
    You can add as much elements as you want as child of this RelativeLayout"
    android:textColor="#FFFFFF"
    android:textSize="20sp" />
</RelativeLayout>
  • Użyłem LinearLayout z androidem: weightSum = "2"
  • Dałem dwóm elementom podrzędnym android: layout_weight = "1" (dałem każdemu 50% przestrzeni nadrzędnej (szerokość i wysokość))
  • Na koniec nadałem dwóm elementom potomnym różne kolory tła, aby uzyskać ostateczny efekt.

Dzięki !

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.