2013-02-12 3 views
5

Ich bin neu in Android-Entwicklung und ich schreibe eine kleine App, um zu verstehen, wie es funktioniert. Ich habe alles funktioniert, aber im Moment kann ich keinen Punkt über benutzerdefinierte Zeichnungszustände bekommen ... lassen Sie mich mit einem Beispielcode erklären.Ich kann nicht Android benutzerdefinierten Zustand zu verstehen

Hier ist meine attrs.xml, in dem ich ein Attribut mit dem Namen "oddMonth" erklären, die boolean:

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

Dann habe ich eine Ansicht custom:

<?xml version="1.0" encoding="utf-8"?> 
<com.example.calendar.DayView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="90dp" 
    android:background="@drawable/dayview_state" > 
    <TextView android:id="@+id/day_number" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentTop="true" 
     android:layout_alignParentRight="true" 
     android:paddingRight="3dp" /> 
</com.example.calendar.DayView> 

Also ich die Zeile "android: background =" @ ziehbar/dayview_state "", die dayview_state.xml Datei verweist:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:easycalendar="http://schemas.android.com/apk/res/com.example.calendar"> 

    <item easycalendar:oddMonth ="true" android:drawable="@drawable/customborder_odd" /> 
    <item easycalendar:oddMonth ="false" android:drawable="@drawable/customborder_even"/> 

</selector> 

So f ar ... für was ich verstehen kann .... Ich habe ein Attribut in attrs.xml definiert. Dieses Attribut repräsentiert den Status für meine benutzerdefinierte Ansicht. Je nach dem booleschen Wert dieses Attributs lädt meine App eines von zwei verschiedenen xml (die hier nicht wichtig sind), von denen jedes ein anderes Zeichen definiert. Der letzte Schritt ist also, meine benutzerdefinierte Klasse zu erstellen! Folgt ein Extrakt aus der Klasse:

public class DayView extends RelativeLayout { 
    private static final int[] STATE_ODD_MONTH = { R.attr.oddMonth }; 
    private boolean mOddmonth = true; 

    public DayView(Context mContext, AttributeSet attrs) { 
     super(mContext, attrs); 
    } 

    @Override 
    protected int[] onCreateDrawableState(int extraSpace) { 
     if (mOddmonth) { 
      final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
      mergeDrawableStates(drawableState, STATE_ODD_MONTH); 

      return drawableState; 
     } else { 
      return super.onCreateDrawableState(extraSpace); 
     } 
    } 

    public boolean isOddMonth() { 
     return mOddmonth; 
    } 

    public void setOddMonth(boolean oddMonth) { 
     if (mOddmonth != oddMonth) { 
      mOddmonth = oddMonth; 

      refreshDrawableState(); 
     } 
    } 
} 

Ok ... so habe ich hier eine private Variable mOddMonth, whith Getter und Setter. Der Konstruktor, mit dem diese Ansicht an anderer Stelle aufgebläht wird. Eine weitere private Variable:

private static final int[] STATE_ODD_MONTH = { R.attr.oddMonth }; 

die ein Array aus nur einem int-Wert gemacht wird, dass ein Verweis auf das Attribut in oddMonth attrs.xml definiert. Und die geerbte Methode:

@Override 
    protected int[] onCreateDrawableState(int extraSpace) { 
     if (mOddmonth) { 
      final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 
      mergeDrawableStates(drawableState, STATE_ODD_MONTH); 

      return drawableState; 
     } else { 
      return super.onCreateDrawableState(extraSpace); 
     } 
    } 

das kann ich nicht wirklich „tief“ verstehen ... na ja, so scheint es mir, dass ich einen Zustand hinzufügen, wenn die lokale Variable mOddMonth wahr ist, sonst nicht. Also ... mein Code funktioniert nur, wenn ich meine dayview_state.xml mit folgenden ersetzen:

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:easycalendar="http://schemas.android.com/apk/res/com.example.calendar"> 

    <item easycalendar:oddMonth ="true" android:drawable="@drawable/customborder_odd" /> 
    <item android:drawable="@drawable/customborder_even"/> 

</selector> 

Auf diese Weise das erste Layout geladen wird, wenn es der Staat ist, andernfalls wird die zweite geladen werden. Aber was ist mit dem Wert des Staates? Nirgendwo in meinem Code setze ich den Wert für diese Variable/Attribut .... wo ich falsch liege?

+0

Es scheint, dass mit dem Standardselektor funktioniert und nur wahre Werte gesetzt: <- default ->

+0

Und so? Was ist mit meinem benutzerdefinierten Selektor? – Stefano

+0

Ich glaube nicht, dass ich Ihre Frage per se verstehe - die Variable mOddmonth wird auf "true" gesetzt, weshalb Sie den Status STATE_ODD_MONTH in onCreateDrawableState erhalten. Also was genau meinst du mit "Was ist mit dem Wert des Staates? Nirgendwo in meinem Code habe ich den Wert für diese Variable/Attribut" –

Antwort

0

Ich würde Ihnen empfehlen, Ihre Frage umformulieren b/c es war nicht klar, was Sie gefragt wurden, bis ich Ihren Kommentar zu @ kcoppock Antwort lesen, die -

„, was ich tun möchte (oder Ich denke, ich sollte tun) ist, diesen Wert irgendwo im Code nach dem aktuellen Status meiner benutzerdefinierten Ansicht, und dann zwingen, es wieder zu rendern .... Oder sollte ich nicht? "

An jedem Punkt können Sie die Ansicht abfragen es ziehbar Zustand mit View.getDrawableState zu bekommen.

Wenn auf dieser Basis, möchten Sie Ihre ziehbar neu zu machen, dann haben Sie mehrere Möglichkeiten.

Zunächst können Sie anrufen Drawable.invalidateSelf. Das müssen Sie aber nur selten tun, da Ihr Drawable normalerweise als Hintergrund einer Ansicht festgelegt wird, der automatisch in der Draw-Methode für Sie gezeichnet wird (nicht auf Draw, was Sie zeichnen). Alles, was Sie in diesem Fall tun müssen, ist, die Ansicht ungültig zu machen (view.invalidate), es wird automatisch Ihren Hintergrund zeichnungsfähig neu zeichnen (und somit Ihre zeichnerische Statusänderung aufheben).

Wenn Sie Ihren Zeichensatz nicht als Hintergrund, sondern für Ihre Hauptzeichnung verwenden, zeichnen Sie Ihre Zeichen in onDraw. Eine einfache myDrawable.draw (Leinwand) sollte ausreichen. Denken Sie jedoch daran, view.invalidate aufzurufen, um die onDraw-Methode auszulösen.

0

Sie haben Recht; Sie werden diesen Wert in Ihrem Konstruktor mit der AttributeSet Variablen zuweisen müssen:

TypedArray values = context.obtainStyledAttributes(attrs, STATE_ODD_MONTH); 
boolean isOddMonth = values.getBoolean(R.attr.oddMonth, false); 
mOddmonth = isOddMonth; 
values.recycle(); 

Ich glaube, das den Trick tun sollten. Ich verwende normalerweise ein declare-styleable-Tag in attrs.xml, anstatt einen int [] zu kodieren, aber ich glaube, es sollte identisch funktionieren.

+0

Vielen Dank für die Antwort! gut ... Aber TypedArray wird nicht verwendet, um den Wert des Attributs abzurufen oddMonth in attrs.xml definiert? Was ich tun möchte (oder ich denke, ich sollte tun), ist, diesen Wert irgendwo im Code entsprechend dem tatsächlichen Status meiner benutzerdefinierten Ansicht zu setzen und dann zu erzwingen, es erneut zu rendern .... Oder sollte ich nicht? – Stefano

+0

Oh, ich verstehe; Ich glaube, ich habe die Frage missverstanden, sorry. – kcoppock

+0

@Stefano meine Antwort unten zu sehen. –

Verwandte Themen