2016-02-26 16 views
6

Anko docs indicaci come aggiungere viste personalizzate a DSL. Ma se la mia vista personalizzata è un gruppo di visualizzazione, sorgono problemi.Come aggiungere gruppi di viste personalizzate a Anko DSL?

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) 
      } 
     } 
    } 
} 

ma se cambio myFrameLayout invocazione a frameLayout funziona OK. Quindi, qual è il modo corretto per utilizzare i gruppi di viste con Anko DSL?

risposta

0

Se diamo un'occhiata alle fonti Anko, possiamo vedere che frameLayout restituisce un'istanza della classe _FrameLayout, dove sono definite queste funzioni lparams. A mio avviso questo è necessario, quindi queste funzioni lparams sono disponibili solo nel codice di creazione del layout.

Nel file Layouts.kt di Anko ci sono queste classi _<ViewGroup> per ogni ViewGroup supportato.

Quindi il modo semplice per supportare un gruppo di viste personalizzato è creare una classe _<ViewGroup> con l'implementazione dei metodi lparams. Il problema è che questa classe _<ViewGroup> spesso contiene molto più codice del mio <ViewGroup> stesso!

E se voglio creare molti gruppi di viste personalizzate, l'aggiunta del supporto Anko per loro diventa un grosso problema con questo approccio. Diciamo che ho classi MyFrameLayout1, MyFrameLayout2, MyFrameLayout3. Sono fondamentalmente FrameLayout e quindi voglio che vengano usati gli stessi parametri di layout. Ma devo creare classi _FrameLayout1, _FrameLayout2, _FrameLaoyt3 che sono solo copia/incolla di _FrameLayout di Anko.

Quindi ho leggermente migliorato questo approccio.Creo un interface _FrameLayout:

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

e ora per sostenere qualsiasi personalizzato FrameLayout sottoclasse non mi resta che:

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

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

Questo riduce copia/incolla molto, durante la creazione di molti gruppi di visualizzazione personalizzata.

+0

Ho archiviato un problema su questo https://github.com/Kotlin/anko/issues/152 – netimen

0

Se si va in qualsiasi lparams dichiarazioni di Anko dal codice, si può vedere che all'interno Anko codice generato DSL, lparams è una funzione di estensione per il T: View che assomiglia a questo:

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 
} 

(e più sovraccarichi per diversi costruttori LayoutParams)

Viene dichiarato all'interno di una classe, quindi è visibile solo nelle funzioni con un ricevitore di quella classe, vedere another question su questo metodo di programmazione DSL.


Al fine di essere in grado di utilizzare lparams per la vostra abitudine ViewGroup in Anko DSL, è necessario dichiarare una funzione simile o funzioni all'interno del vostro codice di visualizzazione personalizzata, che creerà un adeguato LayoutParams per la classe.

Se anche voi volete nascondere lparams funzione da fuori DSL, è possibile effettuare una sottoclasse del vostro MyFrameLayout e utilizzarlo solo in codice DSL, lavorando con MyFrameLayout stesso altrove.

Dopo di che, è possibile chiamare lparams su qualsiasi View all'interno di un lambda, che si passa da init: MyFrameLayout.() -> Unit a fun ViewManager.myFrameLayout.

3

In realtà si è appena estendere anko e dichiarare il vostro CustomView quindi utilizzarlo nel DSL normalmente:

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

quindi utilizzarlo nel DSL normalmente

frameLayout { 
    customView() 
} 
2

se si eredita da esempio _RelativeLayout anziché RelativeLayout, è possibile utilizzare il layout personalizzato come ci si aspetterebbe.