2012-07-02 15 views
20

ho un gruppo di FrameLayout che voglio essere verificabile/selezionabile,personalizzato ispezionabile View che risponde al cambio

Cioè, dopo un clic vorrei il FrameLayout da visualizzare come checked - se premuto di nuovo lo farei piace a diventare un checked. Inoltre, voglio che questa immagine visuale sia descritta come al solito attraverso l'uso di uno <selector>.

io non riesco a ottenere questo lavoro - io non sono sicuro di quello che mi manca:

public class CheckableFrameLayout extends FrameLayout implements Checkable { 
    private boolean mChecked = false; 
    public CheckableFrameLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    public void setChecked(boolean checked) { 
     mChecked = checked; 
     refreshDrawableState(); 
    } 

    public boolean isChecked() { 
     return mChecked; 
    } 

    public void toggle() { 
     setChecked(!mChecked); 
    } 
} 

Il layout della CheckableFrameLayout:

<com.test.view.CheckableFrameLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="@drawable/selector_horizontal" 
    android:clickable="true" > 

Il selettore sostenerla (selector_horizontal.xml):

<item android:drawable="@drawable/selector_vertical_selected" android:state_pressed="false" android:state_checked="true"/> 
<item android:drawable="@drawable/selector_vertical_pressed" android:state_pressed="true" android:state_checked="false"/> 
<item android:drawable="@drawable/selector_vertical_normal" android:state_pressed="false" android:state_checked="false"/> 

Usando il codice di sopra della "state_pressed" sta funzionando benissimo, ma la vista non viene controllata (non è il codice Checkable chiamato come scoperto tramite debug).

risposta

23

aggiungendo il seguente codice a una classe Checkable ammette i selettori di lavorare:

private static final int[] CheckedStateSet = { 
    android.R.attr.state_checked, 
}; 

@Override 
protected int[] onCreateDrawableState(int extraSpace) { 
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
    if (isChecked()) { 
     mergeDrawableStates(drawableState, CheckedStateSet); 
    } 
    return drawableState; 
} 

@Override 
public boolean performClick() { 
    toggle(); 
    return super.performClick(); 
} 
+0

'onCreateDrawableState' non viene chiamato da LinearLayout per qualche motivo. Qualche idea, perché? –

+1

se qualcuno vuole ottenere una soluzione completa, controlla questo repository: https://github.com/shamanland/AndroidLayoutSelector c'è un clic selezionabile/controllabile '' 'LinearLayout''' come un' '' ToggleButton''' –

0

Provare a utilizzare android:state_activated.

<item android:drawable="@color/HighlightColor"  android:state_activated="true"/> 

Dal docs:

valore di Stato per StateListDrawable, impostato quando una vista o della sua controllante è stato "attivato" il che significa che l'utente ha attualmente segnato come di interessi.

+0

Dove dovrei inserire questo tag? Non è disponibile per ''. – Graeme

+0

È proprio come qualsiasi altro stato. Ho aggiunto un esempio alla mia risposta. – Barak

+0

'state_activated' non fa alcuna differenza (è anche API 11) – Graeme

0

Provare a riordinare i tag nel proprio selector_horizontal.xml Questi vengono valutati dall'alto in basso. Sembra che nel tuo caso sia android:state_pressed="false" or android:state_pressed="true" viene applicata e la valutazione non raggiunge mai terza linea con android:state_checked="true" Provare a spostare prima linea per durare:

<item android:drawable="@color/HighlightColor" android:state_pressed="true"/> 
<item android:drawable="@color/selected_color" android:state_checked="true"/> 
<item android:drawable="@android:color/transparent" android:state_pressed="false"/> 
+0

Non fa alcuna differenza: mi sono assicurato che ogni elemento fosse implicito (contiene sia state_pressed che state_checked) in modo che non vengano confusi. – Graeme

0

Oltre alla risposta di Graeme sopra fare la seguente modifica alternare()

@Override 
public void toggle() { 
    mChecked = !mChecked; 
    refreshDrawableState(); 
} 
+0

Ho incluso nella risposta originale – Graeme

+0

l'unica aggiunta qui è che dobbiamo chiamare refreshDrawableState() anche in toggle(). – sujith

+1

duplicazione non necessaria del codice. – Graeme

0

La soluzione di Graeme non ha funzionato da me sotto Android 4.0.3 (e suppongo che non funzionerà anche con 4.0). Invece si può cambiare state_checked-state_activated:

<selector xmlns:android="http://schemas.android.com/apk/res/android"> 

    <item android:drawable="@drawable/activated_image" android:state_pressed="false" android:state_activated="true" /> 
    <item android:drawable="@drawable/not_activated_image" android:state_pressed="false" android:state_activated="false"/> 

</selector> 

e utilizzare setActivated all'interno del vostro setChecked:

@Override 
public void setChecked(boolean checked) { 
    mChecked = checked; 
    setActivated(checked); 
} 

e questo è tutto. L'implementazione di onCreateDrawableState non è richiesta qui.

+0

Vedere i [documenti] (http://developer.android.com/reference/android/graphics/drawable/StateListDrawable.html#attr_android%3astate_activated) - "Questa è una rappresentazione alternativa di state_checked per quando lo stato dovrebbe essere propagato lungo la gerarchia della vista. ", Il suono è così utile solo se vuoi che i bambini della tua vista rispondano' true' se il genitore è selezionato. – Graeme

+0

Buono a sapersi. – Graeme

+0

La soluzione di Graeme funziona per me per un pulsante controllabile (ho anche aggiunto refreshDrawableState() per setChecked() e toggle() come suggerito da sujith. – Ridcully

4

Ecco un esempio funzionante completo per un CheckableButton. Funziona anche su Android 4.2.

public class CheckableButton extends Button implements Checkable { 

    private static final int[] CheckedStateSet = { android.R.attr.state_checked }; 

    private boolean mChecked = false; 

    public CheckableButton(Context context) { 
     super(context); 
    } 

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

    public CheckableButton(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    public boolean isChecked() { 
     return mChecked; 
    } 

    @Override 
    public void setChecked(boolean checked) { 
     mChecked = checked; 
     refreshDrawableState(); 
    } 

    @Override 
    public void toggle() { 
     mChecked = !mChecked; 
     refreshDrawableState(); 
    } 

    @Override 
    protected int[] onCreateDrawableState(int extraSpace) { 
     final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
     if (isChecked()) { 
      mergeDrawableStates(drawableState, CheckedStateSet); 
     } 
     return drawableState; 
    } 
}