Özel bir düğme durumu nasıl eklenir


133

Örneğin, varsayılan düğme, durumları ve arka plan görüntüleri arasında aşağıdaki bağımlılıklara sahiptir:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_window_focused="false" android:state_enabled="true"
        android:drawable="@drawable/btn_default_normal" />
    <item android:state_window_focused="false" android:state_enabled="false"
        android:drawable="@drawable/btn_default_normal_disable" />
    <item android:state_pressed="true" 
        android:drawable="@drawable/btn_default_pressed" />
    <item android:state_focused="true" android:state_enabled="true"
        android:drawable="@drawable/btn_default_selected" />
    <item android:state_enabled="true"
        android:drawable="@drawable/btn_default_normal" />
    <item android:state_focused="true"
        android:drawable="@drawable/btn_default_normal_disable_focused" />
    <item
        android:drawable="@drawable/btn_default_normal_disable" />
</selector>

Kendi özel durumumu (smth like android:state_custom) nasıl tanımlayabilirim , böylece düğme görsel görünümümü dinamik olarak değiştirmek için kullanabilir miyim?


İki parola kutusunun ne zaman eşleşip küçük bir onay işareti göstereceğini belirlemek için bir Metin Düzenleme görünümü için ekstra durumlar istiyordum.
Nathan Schwermann

Yanıtlar:


276

@ (Ted Hopp) ile gösterilen çözüm işe yarıyor, ancak biraz düzeltilmesi gerekiyor: seçicide, öğe durumları bir "app:" önekine ihtiyaç duyar, aksi takdirde şişirici ad alanını doğru bir şekilde tanımaz ve sessizce başarısız olur; en azından bana olan bu.

Burada tüm çözümü biraz daha ayrıntıyla birlikte bildirmeme izin verin:

Önce "res / values ​​/ attrs.xml" dosyasını oluşturun:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="food">
        <attr name="state_fried" format="boolean" />
        <attr name="state_baked" format="boolean" />
    </declare-styleable>
</resources>

Ardından özel sınıfınızı tanımlayın. Örneğin, "Button" sınıfından türetilmiş bir "FoodButton" sınıfı olabilir. Bir kurucu uygulamanız gerekecek; Şişirici tarafından kullanılan gibi görünen bunu uygulayın:

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

Türetilmiş sınıfın üstünde:

private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};

Ayrıca, durum değişkenleriniz:

private boolean mIsFried = false;
private boolean mIsBaked = false;

Ve birkaç pasör:

public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}

Ardından "onCreateDrawableState" işlevini geçersiz kılın:

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
    if (mIsFried) {
        mergeDrawableStates(drawableState, STATE_FRIED);
    }
    if (mIsBaked) {
        mergeDrawableStates(drawableState, STATE_BAKED);
    }
    return drawableState;
}

Son olarak, bu bulmacanın en hassas parçası; Widget'ınız için arka plan olarak kullanacağınız StateListDrawable'ı tanımlayan seçici. Bu "res / drawable / food_button.xml" dosyasıdır:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
    app:state_baked="true"
    app:state_fried="false"
    android:drawable="@drawable/item_baked" />
<item
    app:state_baked="false"
    app:state_fried="true"
    android:drawable="@drawable/item_fried" />
<item
    app:state_baked="true"
    app:state_fried="true"
    android:drawable="@drawable/item_overcooked" />
<item
    app:state_baked="false"
    app:state_fried="false"
    android:drawable="@drawable/item_raw" />
</selector>

Standart android durumlarında "android:" önekini kullanırdınız, oysa "app:" önekine dikkat edin. XML ad alanı, şişirici tarafından doğru bir yorumlama için çok önemlidir ve öznitelikleri eklediğiniz projenin türüne bağlıdır. Bu bir uygulamaysa, com.mydomain.mypackage yerine uygulamanızın gerçek paket adını yazın (uygulama adı hariçtir). Bir kitaplıksa, "http://schemas.android.com/apk/res-auto" kullanmanız gerekir (ve Araçlar R17 veya üzerini kullanıyor olmanız gerekir), aksi takdirde çalışma zamanı hataları alırsınız.

Birkaç not:

  • Görünüşe göre "renewDrawableState" işlevini çağırmanıza gerek yok, en azından çözüm benim durumumda olduğu gibi çalışıyor

  • Özel sınıfınızı bir düzen xml dosyasında kullanmak için, tam olarak nitelenmiş adı belirtmeniz gerekir (örn. Com.mydomain.mypackage.FoodButton)

  • Daha karmaşık durum kombinasyonlarını temsil etmek için, standart durumları (örn. Android: basılı, android: etkin, android: seçili) özel durumlarla karıştırabilirsiniz.


3
Güncelleme: özel sınıf, Button yerine TextView'dan türetilirse, yenilemeDrawableState çağrısı gerekli görünür, aksi takdirde parçacık görünümü güncellenmez. Çağrı, ayarlayıcılara yerleştirilecektir. Diğer sınıfları denemedim. Bir froyo cihazında gerçekleştirilen testler.
Giorgio Barchiesi

17
refreshDrawableStateKesinlikle önemlidir. Ne zaman gerçekten ihtiyaç duyulduğundan tam olarak emin değilim. Ancak benim durumumda, durumu programlı olarak ayarlarken buna ihtiyaç vardı. Sanırım, muhtemelen onTouchEvent'te View sınıfından otomatik olarak çağrılıyor. Bunu setSelected yöntemine eklesem iyi olur.
buergi

1
GiorgioBarchiesi, iki özel Düğmem var ve bir düğmenin onClick olayından her iki düğmenin de durumunu değiştirmeye çalıştığımda, yalnızca tıklanan düğme değişecek, bence @buergi, yenilemeDrawableState yönteminin onClickEvent. Harika öğreticiniz için tekrar teşekkürler :)
Bolton

2
Ancak olmayan özel durumları nasıl kullanabilirsiniz boolean? Yoksa seçiciler yalnızca boolelerde mi çalışıyor?
Peterdk

2
O nasıl çalışır? Demek istediğim, özellik doğru / yanlış olarak nasıl güncellenir? Kim güncelliyor? Drawablestate'i birleştirmek, yalnızca yerel değişken doğruysa, niteliğin durumunu veya değerini günceller mi? R.attr.state_fried'i tam olarak hangi kod güncelleyecektir?
kAmol

10

Bu iş parçacığı , düğmelere ve benzerlerine özel durumların nasıl ekleneceğini gösterir. (Tarayıcınızda yeni Google gruplarını göremiyorsanız, burada ileti dizisinin bir kopyası vardır .)


+1 çok teşekkürler Ted! Şu anda sorunun kaynağı gitti, bu yüzden gerçek uygulamaya geçmedim. Ancak müşterim buna tekrar dönerse, beni gösterdiğin yolu deneyeceğim.
Vit Khudenko

Tam olarak ihtiyacım olan şey gibi görünüyor, ancak özel durumlarım için durum listesi
çekilişleri değişmiyor, bir

RefreshDrawableState () 'i mi çağırıyorsunuz?
Ted Hopp

Bağlantılar öldü.
Mitch

@Mitch - Bu çok kötü. Bakalım bazı yedek bağlantılar bulabilir miyim? Değilse, temelde faydasız olduğu için bu yanıtı sileceğim. Bu arada, kabul edilen cevap gerekli tüm bilgilere sahiptir.
Ted Hopp

7

Lütfen refreshDrawableStateUI iş parçacığı içinde aramayı unutmayın :

mHandler.post(new Runnable() {
    @Override
    public void run() {
        refreshDrawableState();
    }
});

Her şey doğru görünmesine rağmen düğmemin neden durumunu değiştirmediğini anlamak çok zamanımı aldı.


bu işleyiciyi nereye veya ne zaman göndermeliyim?
Arthur Melo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.