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ů.






