2010-05-21 3 views
32

Ich lerne über die Verwendung von benutzerdefinierten Ansichten der folgenden Optionen:Android Benutzerdefinierte Ansicht Constructor

http://developer.android.com/guide/topics/ui/custom-components.html#modifying

Die Beschreibung sagt:

Klasse Initialisierung Wie immer die Super wird zuerst genannt. Außerdem ist dies kein Standardkonstruktor, sondern ein parametrisierter. Der EditText ist mit diesen Parametern erstellt, wenn es ist über eine XML-Layout-Datei, aufgeblasen wird, so muss unser Konstruktor sowohl nehmen sie und übergibt sie an die Superklasse Konstruktor sowie.

Gibt es eine bessere Beschreibung? Ich habe versucht herauszufinden, wie der/die Konstruktor (en) aussehen sollte und ich habe 4 mögliche Entscheidungen (siehe Beispiel am Ende des Posts). Ich bin nicht sicher, was diese 4 Wahlen tun (oder nicht tun), warum ich sie implementieren sollte, oder was die Parameter bedeuten. Gibt es eine Beschreibung von diesen?

public MyCustomView() 
{ 
    super(); 
} 

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

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

public MyCustomView(Context context, AttributeSet attrs, Map params) 
{ 
    super(context, attrs, params); 
} 
+0

Ähnliche Fragen hier: http://stackoverflow.com/questions/9195713/do-i-need-all-three-constructors-for-an-android-custom-view – mbonnin

Antwort

61

Sie brauchen nicht die erste, da das einfach nicht funktioniert.

Die dritte wird Ihre benutzerdefinierte View wird von XML-Layout-Dateien verwendbar sein. Wenn Ihnen das egal ist, brauchen Sie es nicht.

Der vierte ist einfach falsch, AFAIK. Es gibt keinen View Konstruktor, der einen Map als dritten Parameter nimmt. Es gibt einen, der einen int als dritten Parameter verwendet, um den Standardstil für das Widget zu überschreiben.

Ich neige dazu, die this() Syntax verwenden diese kombinieren:

public ColorMixer(Context context) { 
    this(context, null); 
} 

public ColorMixer(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
} 

public ColorMixer(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    // real work here 
} 

Sie können den Rest dieses Codes in this book example sehen.

+7

super (Kontext, attrs) und super (Kontext, attrs, 0) funktioniert differentiell für mich. Der erste ist in Ordnung, aber der zweite entfernt den ursprünglichen Stil aus einer Ansicht. Ist es ein Fehler in neueren Versionen von Android? – broot

+9

Ja, mein 'this()' Ansatz hatte Fehler. Machen Sie einfach eine einfache Kette zu der Oberklasse (z. B. "super (Kontext, attrs)") und ordnen Sie einen Aufruf einer gemeinsamen privaten Methode (z. B. "init();") in jedem Konstruktor zu. Ein Beispiel finden Sie unter https://github.com/commonsguy/cwac-colormixer/blob/master/src/com/commonsware/cwac/colormixer/ColorMixer.java. – CommonsWare

+0

Ja, ich habe genau das Gleiche gemacht, aber im ersten Konstruktor dieses (context, null) aufgerufen. Ein Fehler besteht darin, dass Sie die letzten Felder in beiden Konstruktoren initialisieren müssen - das können Sie in der Methode init() nicht tun. – broot

11

Hier ist ein mein Muster (eine benutzerdefinierte Erstellung ViewGoup hier, aber immer noch):

// CustomView.java 

public class CustomView extends LinearLayout { 

    public CustomView(Context context) { 
     super(context); 
     init(context); 
    } 

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

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

    private void init(Context ctx) { 
     LayoutInflater.from(ctx).inflate(R.layout.view_custom, this, true); 
      // extra init 
    } 

} 

und

// view_custom.xml 

<merge xmlns:android="http://schemas.android.com/apk/res/android"> 
    <!-- Views --> 
</merge> 
+0

Dies ist nicht so effektiv wie die @CommonsWare-Lösung, da Sie nicht zulassen, dass Felder als 'final' markiert sind, während die Verwendung einer Kette von this() -Aufrufen erfolgt. – greg7gkb

+3

@ greg7gkb Allerdings @ Commonsware Lösung ist fehlerhaft. Sie müssen jedes separate Super aufrufen und eine 'init()' – Blundell

+0

verwenden Keine Notwendigkeit, den Kontext an init() übergeben, können Sie einfach aufrufen getContext() – Ran

6

Wenn Sie Ihre individuelle hinzufügen View von xml wie:

<com.mypack.MyView 
     ... 
     /> 

müssen Sie den öffentlichen KonstruktorMyView(Context context, AttributeSet attrs), sonst werden Sie ein Exception wenn Android versucht, inflate Ihre View bekommen.

Und wenn Sie fügen Sie Ihre View von xml und auch die android:styleattribute angeben:

<com.mypack.MyView 
     style="@styles/MyCustomStyle" 
     ... 
     /> 

Sie auch die dritte öffentlichen KonstruktorMyView(Context context, AttributeSet attrs,int defStyle) müssen.

Der dritte Konstruktor in der Regel verwendet, wenn Sie einen Stil erweitert und angepasst werden, und dann würden Sie das style zu einem bestimmten View in Ihren Layouts

Weitere Details

public MyView(Context context, AttributeSet attrs) { 
      //Called by Android if <com.mypack.MyView/> is in layout xml file without style attribute. 
      //So we need to call MyView(Context context, AttributeSet attrs, int defStyle) 
      // with R.attr.customViewStyle. Thus R.attr.customViewStyle is default style for MyView. 
      this(context, attrs, R.attr.customViewStyle); 
    } 

gesetzt gerne See this

+0

Ich habe einige benutzerdefinierte Ansichten im selben Layout. Wie kann ich dem Konstruktor einen Index übergeben, der angibt, zu welcher der benutzerdefinierten Ansichten er gehört? – Zvi

+0

Sie sollten TypedArray und styleable Attribute lesen. http://stackoverflow.com/questions/11039829/how-to-pass-view-reference-to-android-custom-view – Nepster

+0

@Nepstar, las ich diesen Beitrag und ich habe nicht verstanden, wie es mein Problem lösen wird, weil Stilbare Attribute sind, soweit ich es verstanden habe, statische Eigenschaften, die vor der Ausführung der App definiert sind. Daher erhalten alle Instanzen meiner benutzerdefinierten Komponenten die gleichen Daten, während ich für jede laufende Komponente eine eindeutige ID benötige. – Zvi