2016-02-26 15 views
6

Anko docs sagen Sie uns, wie Sie benutzerdefinierte Ansichten zu DSL hinzufügen. Aber wenn meine benutzerdefinierte Ansicht eine Ansichtsgruppe ist, treten Probleme auf.Wie fügt man Anko DSL benutzerdefinierte Ansichtsgruppen hinzu?

class MyFrameLayout(context: Context) : FrameLayout(context) 

fun ViewManager.myFrameLayout(init: MyFrameLayout.() -> Unit = {}) = ankoView({ MyFrameLayout(it) }, init) 

class MyUI : AnkoComponent<Fragment> { 
    override fun createView(ui: AnkoContext<Fragment>) = with(ui) { 

     myFrameLayout { 
      textView("hello").lparams { // error: Unresolved reference: lparams 
       bottomMargin = dip(40) 
      } 
     } 
    } 
} 

aber wenn ich myFrameLayout Anrufung frameLayout ändern funktioniert es OK. Was ist der richtige Weg, View-Groups mit Anko DSL zu nutzen?

Antwort

0

Wenn wir uns Anko-Quellen ansehen, können wir sehen, dass frameLayout tatsächlich eine Instanz der _FrameLayout Klasse zurückgibt, wo diese lparams Funktionen definiert sind. Nach meinem Verständnis ist dies erforderlich, so dass diese lparams Funktionen nur im Layout-Baucode verfügbar sind.

In Ankos Layouts.kt Datei gibt es diese _<ViewGroup> Klassen für jede unterstützte ViewGroup.

So die einfache Möglichkeit, eine benutzerdefinierte Ansicht Gruppe zu unterstützen, ist eine _<ViewGroup> Klasse mit lparams Methoden Implementierung zu erstellen. Das Problem ist, dass diese _<ViewGroup> Klasse oft viel mehr Code enthält als meine <ViewGroup> selbst!

Und wenn ich viele benutzerdefinierte Ansichtsgruppen erstellen möchte, wird das Hinzufügen von Anko-Unterstützung für sie zu einem großen Schmerz bei diesem Ansatz. Nehmen wir an, ich habe MyFrameLayout1, MyFrameLayout2, MyFrameLayout3 Klassen. Sie sind im Grunde FrameLayout 's, so möchte ich die gleichen Layout-Parameter mit ihnen verwendet werden. Aber ich muss _FrameLayout1, _FrameLayout2, _FrameLaoyt3 Klassen erstellen, die nur kopieren/einfügen von Ankos _FrameLayout sind.

Also habe ich diesen Ansatz etwas verbessert.Ich erstelle ein interface _FrameLayout:

interface _FrameLayout { 
    // copy/paste from Anko's _FrameLayout 
} 

und jetzt alle benutzerdefinierten FrameLayout Unterklasse zu unterstützen, ich habe gerade zu:

class _MyFrameLayout(ctx: Context) : MyFrameLayout(ctx), _FrameLayout 

fun ViewManager.myFrameLayout(init: _MyFrameLayout.() -> Unit = {})= ankoView({ _MyFrameLayout(it) }, init) 

Diese Kopie reduziert/viel einfügen, wenn viele benutzerdefinierte Ansicht Gruppen zu schaffen.

+0

Ich habe ein Problem darüber https://github.com/Kotlin/anko/issues/152 eingereicht – netimen

0

Wenn Sie zu einem Anko der lparams Erklärungen aus dem Code zu gehen, können Sie sehen, dass innerhalb Anko DSL-Code generiert, lparams ist eine Erweiterungsfunktion für T: View, die wie folgt aussieht:

fun <T: View> T.lparams(
     width: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 
     height: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 
     init: android.widget.FrameLayout.LayoutParams.() -> Unit = defaultInit 
): T { 
    val layoutParams = android.widget.FrameLayout.LayoutParams(width, height) 
    layoutParams.init() 
    [email protected] = layoutParams 
    return this 
} 

(und mehr Überlastungen für verschiedene LayoutParams Konstruktoren)

Es ist innerhalb einer Klasse deklariert, so dass es nur in Funktionen mit einem Empfänger dieser Klasse sichtbar ist, siehe another question über diese Methode der DSL-Programmierung.


Um in der Lage sein, zu verwenden lparams für Ihre benutzerdefinierten ViewGroup in Anko DSL, müssen Sie in Ihrem benutzerdefinierten Ansicht Code eine ähnliche Funktion oder Funktionen deklarieren, die eine entsprechendes LayoutParams für Ihre Klasse zu schaffen.

Wenn Sie auch lparams Funktion von außerhalb des DSL ausblenden möchten, können Sie eine Unterklasse Ihrer MyFrameLayout machen und es in DSL-Code verwenden nur, die Arbeit mit MyFrameLayout sich anderswo.

Danach können Sie lparams auf jedem View in einem Lambda nennen, die Sie als init: MyFrameLayout.() -> Unit zu fun ViewManager.myFrameLayout passieren.

3

Eigentlich müssen Sie nur anko erweitern und erklären sich dann Custom es im DSL verwenden normalerweise:

public inline fun ViewManager.customView() = customView {} 
public inline fun ViewManager.customView(init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, init) 

es dann im DSL verwenden normalerweise

frameLayout { 
    customView() 
} 
2

, wenn Sie zum Beispiel aus erben _RelativeLayout anstelle von RelativeLayout können Sie Ihr benutzerdefiniertes Layout wie erwartet verwenden.

Verwandte Themen