Ve třetím díle mini série o knihovně Anko budeme vylepšovat naši demo aplikaci, aby vypadala o něco lépe po stránce designu. Také se ale naučíme, jaké další extension funkce Anko nabízí, například k nastavení layoutu pro portrait/landscape mód.
Úvod do knihovny Anko pro Android (3/4)
V prvním článku jsme si řekli něco o vytvoření UI, které jsme definovali jako samostatné komponenty (AnkoComponent). Taky jsme si ukázali, jak je lze používat uvnitř aktivit. V předchozím článku jsme přidali do naší demo aplikace trochu té logiky. Nyní se vrátíme trochu zpátky a zaměříme se na vylepšení UI.
Přehled dílů série:
1. Vytvoření projektu v Android Studio 3 a první UI
2. Tlačítka, toasty, dialogy, intenty, uživatelská rozhraní a práce na pozadí (background threads)
3. Vylepšujeme naše UI
4. Fragmenty & RecyclerView
Jako první přidáme padding
do root UI elementu (vertical layout) v SignInView komponentě
:
// SignInView.createView verticalLayout { padding = dip(20) ... }
Výše uvedené DSL by v XML vypadalo následovně:
<LinearLayout android:padding="20dip" ... />
Všimněte si, že v SignInView
komponentě nastavuje stejnou velikost textu oběma komponentám (username a password), konkrétně textSize = 24f
.
val username = editText { ... textSize = 24f } val password = editText { ... textSize = 24f }
Anko obsahuje další užitečnou extension funkci: aplikování parametrů do view rekurzivně, tedy applyRecursively{}
. Můžeme tak nastavit textSize
parametr rekurzivně všem UI komponentám, například typu EditText
:
verticalLayout { padding = dip(20) ... val username = editText { id = R.id.usernameEditText hintResource = R.string.sign_in_username }.lparams(width = matchParent, height = wrapContent) val password = editText { id = R.id.passwordEditText hintResource = R.string.signIn_password }.lparams(width = matchParent, height = wrapContent) button {...}.lparams(width = matchParent, height = wrapContent) }.applyRecursively { view -> when (view) { is EditText -> view.textSize = 24f } }
V dalším kroku přidáme do SignInView
komponentu pro skrolování a zarovnáme formulář na střed. Po dokončení těchto kroků bude UI vypadat následovně:
Nebudu popisovat každou změnu krok za krokem, ale rozebereme si ty nejdůležitější části. Zkopírujte si následující kód, použijte ho ve vaší demo aplikaci a vyzkoušejte aplikaci spustit.
ackage com.example.android.anko.sample.sign_in import android.os.Build import android.support.v4.content.ContextCompat import android.view.Gravity import android.view.ViewGroup import android.widget.EditText import android.widget.LinearLayout import com.example.android.anko.sample.R import org.jetbrains.anko.* /** * @author vsouhrada * @since 0.1.0 * @see[AnkoComponent] * @see[SignInActivity] */ class SingInView : AnkoComponent<SignInActivity> { private lateinit var ankoContext: AnkoContext<SignInActivity> override fun createView(ui: AnkoContext<SignInActivity>) = with(ui) { ankoContext = ui verticalLayout { this.gravity = Gravity.CENTER scrollView { verticalLayout { verticalLayout { id = R.id.formLogin gravity = Gravity.CENTER padding = dip(20) lparams(width = dip(300), height = matchParent) { this.gravity = Gravity.CENTER // API >= 16 doFromSdk(version = Build.VERSION_CODES.JELLY_BEAN) { background = ContextCompat.getDrawable(ctx, android.R.color.white) } clipToPadding = false bottomMargin = dip(16) } val username = editText { id = R.id.usernameEditText hintResource = R.string.sign_in_username }.lparams(width = matchParent, height = wrapContent) val password = editText { id = R.id.passwordEditText hintResource = R.string.signIn_password }.lparams(width = matchParent, height = wrapContent) button { id = R.id.signIn_button textResource = R.string.signIn_button onClick { handleOnSignInButtonPressed(username = username.text.toString(), password = password.text.toString()) } }.lparams(width = matchParent, height = wrapContent) }.applyRecursively { view -> when (view) { is EditText -> view.textSize = 24f } } }.lparams(width = matchParent, height = matchParent) }.lparams(width = matchParent, height = wrapContent) } } private fun handleOnSignInButtonPressed(username: String, password: String) { with(ankoContext) { if (username.isBlank() or password.isBlank()) { alert(title = R.string.sigIn_alert_invalid_user_title, message = R.string.sigIn_alert_invalid_user_message) { positiveButton(R.string.dialog_button_close) {} }.show() } else { owner.authorizeUser(username, password) } } } fun showAccessDeniedAlertDialog() { with(ankoContext) { alert(title = R.string.sigIn_alert_access_denied_title, message = R.string.sigIn_alert_access_denied_msg) { positiveButton(R.string.dialog_button_close) {} }.show() } } }
Řádek 26: sem jsme přidali nový parametr gravity
se zarovnáním na střed
Řádek 28: přidána scrollView
komponenta s vnořenou verticalLayout
obalující Sign in formulář
Řádek 32: zde se nově nachází naše původní verticalLayout
, do které jsme přidali opět parametr gravity
se zarovnáním na střed
Řádek 37: nastavení 300dp pro velikost formuláře
Poznámka: Asi vás zajímá, proč máme definici lparams
na řádku 37 uvnitř verticalLayout
komponenty a nemáme ji podle doporučení za ukončením layoutu. Důvodem je, že nastavení délky layout ve verzi 0.9 funguje pouze touto mnou uvedenou definicí. Navíc to bude fungovat pouze pokud přesuneme daný kód do funkce apply
:
... verticalLayout { .... }.apply { lparams(width = dip(300), height = matchParent) { this.gravity = Gravity.CENTER // API >= 16 doFromSdk(version = Build.VERSION_CODES.JELLY_BEAN) { background = ContextCompat.getDrawable( ctx, android.R.color.white) } clipToPadding = false bottomMargin = dip(16) } }
Vraťme se k původnímu kódu bez použití funkce apply. Na řádku 40 si můžete všimnout následujícího kódu:
// API >= 16 doFromSdk(version = Build.VERSION_CODES.JELLY_BEAN) { background = ContextCompat.getDrawable( ctx,android.R.color.white) }
Použití View#setBackground
vyžaduje API >= 16. Anko obsahuje několik funkcí pro tyto účely a pro nastavení při různém natočení mobilního zařízení (portrait a landscape):
// Code inside for this block code is from original Anko //Documentation configuration(screenSize = ScreenSize.LARGE, orientation = Orientation.LANDSCAPE) { /* This code will be only executed if the screen is large and its orientation is landscape */ }
V našem případě, kdy nerozlišujeme natočení, můžeme použít také následující zápis:
configuration(fromSdk = Build.VERSION_CODES.JELLY_BEAN) { background = ContextCompat.getDrawable( ctx, android.R.color.white) }
Shrnutí 3. části
Tentokrát jsme se naučili, jak přidat další parametry do UI komponent (padding, gravity a další) a přidali jsme také scroll view komponentu. Taky jsme si vyzkoušeli, jak můžeme tyto parametry aplikovat rekurzivně (třeba textSize).
Na závěr jsme si ukázali, jak se v Anko knihovně dá zacházet s portrait/landscape módem a jak můžeme odlišit, pro jaké Android API se má daný kód použít.
V příštím článku se naučíme práci s fragmenty. To znamená, že si řekneme, co nám Anko poskytuje za vylepšení při psaní fragmentů.