Android Anko布局
在本教程中,我们将讨论和实现Android Anko Layouts模块,该模块是Anko库的一部分。
Anko是一个领域特定的语言库,旨在使用Kotlin更快更轻松地进行Android开发。
Anko布局
通过XML构建UI布局一直是Android开发中最具挑战性的部分之一。
它不是安全/无效类型。
此外,将XML布局加载到设备上需要花费时间和精力。
当然,您可以在"活动"中以编程方式开发布局,但这甚至很复杂。
幸运的是,我们现在有Anko Layouts!您可以使用它创建一个更简单的UI。
例如,我们可以在Activity中使用Anko布局构建以下UI。
package net.androidly.androidlyankolayouts
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import org.jetbrains.anko.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
verticalLayout{
editText {
hint = "Enter your name"
}
button("ECHO"){
setOnClickListener {
toast("Button clicked")
}
}
}
}
}
我们创建了一个LinearLayout,用于垂直显示元素。
另外,在Anko Layouts语法内,我们还设置了按钮点击监听器。
使用Anko Layouts,我们可以将布局代码和应用程序逻辑保持在一起,而不必在活动中链接XML。
等效的XML代码是:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter your name"
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ECHO"
</LinearLayout>
Anko Layouts是XML布局的良好替代品,因为它使逻辑易于编写和维护。
Anko Layouts也有很多缺点:
- 它们不显示XML之类的布局预览。
尽管您可以从Android Studio中的"偏好设置"下载Anko支持插件: - 缺乏像XML这样的格式。
话虽如此,Anko Layouts确实允许您在Anko Layouts DSL语法中包括XML布局。
现在,让我们深入研究Anko Layouts的各种功能。
入门
在build.gradle文件中添加以下依赖项:
implementation "org.jetbrains.anko:anko-sdk25:0.10.4" implementation "org.jetbrains.anko:anko-appcompat-v7:0.10.4"
代替sdk25,您还可以放置:sdk15,sdk19,sdk21,sdk23。
上面的依赖项也包含Anko Common模块。
布局和布局参数
您可以将我们前面讨论的所有主要视图组用作容纳小部件的容器。
水平LinearLayout
linearLayout{
editText {
hint = "Enter your name"
}
button("ECHO")
{
setOnClickListener {
toast("Button clicked")
}
}
}
这将水平排列视图。
Anko布局看起来像:
我们可以将布局参数设置为:
linearLayout {
layoutParams = ViewGroup.LayoutParams(matchParent, matchParent)
padding = dip(16)
this.gravity = Gravity.CENTER
weightSum = 1.0f
editText {
hint = "Enter your name"
gravity = Gravity.END
}.lparams(width = 0, height = wrapContent)
{
weight = 0.6f
}
button("ECHO")
{
setOnClickListener {
toast("Button clicked")
}
}.lparams(width = 0, height = wrapContent) {
weight = 0.4f
}
}
在上面的代码中,我们通过布局权重设置LinearLayout内部的小部件的宽度。
默认情况下,以上代码中LinearLayout的layoutParams仅是matchParent,因此您可以摆脱它。
如果指定lparams(),但省略了小部件的宽度和/或者高度,则它们的默认值均为wrapContent
相对布局
val ID_1 = 1
relativeLayout {
button {
id = ID_1
text = "Button $ID_1"
gravity = Gravity.START + Gravity.CENTER_VERTICAL
}.lparams {
centerInParent()
}
button("Button 2").lparams { below(ID_1) }
button("Button 3").lparams {
alignParentBottom()
alignParentEnd()
}
}
请注意,要设置多个重力,我们在Anko Layouts中使用+。
在XML中,我们使用|
尝试使用FrameLayout和ScrollView作为自己的布局根来构建Anko布局!
Anko ConstraintLayout
要在Anko Layouts中使用ConstraintLayout,请在您的build.gradle中添加以下依赖项。
implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation "org.jetbrains.anko:anko-constraint-layout:0.10.4"
以下代码演示了具有TextView和ImageView的Anko布局。
val ID_11 = 11
val ID_22 = 22
constraintLayout {
val image = imageView(R.mipmap.ic_launcher) {
id = ID_11
scaleType = ImageView.ScaleType.CENTER_CROP
}.lparams(dip(48), dip(48))
val textLabel = textView {
id = ID_22
text = "Hello"
padding = dip(5)
}.lparams(wrapContent, wrapContent)
applyConstraintSet {
image {
connect(
ConstraintSetBuilder.Side.TOP to ConstraintSetBuilder.Side.TOP of PARENT_ID,
ConstraintSetBuilder.Side.LEFT to ConstraintSetBuilder.Side.LEFT of PARENT_ID,
ConstraintSetBuilder.Side.RIGHT to ConstraintSetBuilder.Side.RIGHT of PARENT_ID,
ConstraintSetBuilder.Side.BOTTOM to ConstraintSetBuilder.Side.BOTTOM of PARENT_ID
)
verticalBias = 0.2f
}
textLabel {
connect(
ConstraintSetBuilder.Side.TOP to ConstraintSetBuilder.Side.BOTTOM of image margin dip(10),
ConstraintSetBuilder.Side.RIGHT to ConstraintSetBuilder.Side.RIGHT of PARENT_ID margin dip(16),
ConstraintSetBuilder.Side.LEFT to ConstraintSetBuilder.Side.LEFT of PARENT_ID margin dip(16)
)
}
}
}
在上面的代码中,我们将ImageView设置为屏幕的中心,但带有verticalBias。
我们在其下方添加了TextView。
Anko协调器布局
要使用CoordinatorLayout,请在build.gradle中添加以下依赖项。
implementation 'com.android.support:design:28.0.0-alpha3' implementation "org.jetbrains.anko:anko-design:0.10.4"
注意:以上是编写本教程时可用的版本。
以下代码演示了如何使用Anko Layouts进行CoordinatorLayout。
package net.androidly.androidlyankolayouts
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.design.widget.AppBarLayout.LayoutParams.*
import android.support.v4.content.ContextCompat
import android.support.v4.view.GravityCompat
import android.view.Gravity
import android.widget.Toolbar
import org.jetbrains.anko.*
import org.jetbrains.anko.design.appBarLayout
import org.jetbrains.anko.design.coordinatorLayout
import org.jetbrains.anko.design.floatingActionButton
class MainActivity : AppCompatActivity() {
var toolbar: Toolbar? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
coordinatorLayout {
appBarLayout {
toolbar = themedToolbar(R.style.ThemeOverlay_AppCompat_Dark_ActionBar) {
backgroundResource = R.color.colorPrimary
textView {
text = "HELLO"
}
}.lparams(width = matchParent) {
scrollFlags = SCROLL_FLAG_SNAP or SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS
}
}.lparams(width = matchParent)
floatingActionButton {
imageResource = android.R.drawable.ic_dialog_email
backgroundColor = ContextCompat.getColor(ctx, R.color.colorPrimary)
}
.lparams(wrapContent, wrapContent) {
gravity = Gravity.BOTTOM or GravityCompat.END
horizontalMargin = dip(25)
verticalMargin= dip(25)
}
}
}
}
horizontalMargin设置左边距和右边距。verticalMargin将边距设置为顶部和底部。topMargin,bottomMargin,leftMargin和rightMargin用于为各个边设置边距。
具有自定义视图的警报对话框
package net.androidly.androidlyankolayouts
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.Gravity
import android.widget.EditText
import org.jetbrains.anko.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verticalLayout {
var inputName: EditText? = null
gravity = Gravity.CENTER
lparams(height = matchParent, width = matchParent) {
margin = dip(16)
}
button {
text = "Alert Dialog With Edit Text"
setOnClickListener {
alert {
title = "Title"
message = "Message"
customView {
inputName = editText {
hint = "Enter your name"
}
}
yesButton {
toast("Name is ${inputName?.text}")
}
}.show()
}
}
}
}
}
主题块
Anko DSL提供所有UI小部件的主题版本。
您可以在小部件上将预定义或者自定义主题设置为:
verticalLayout {
themedButton("Ok", theme = android.R.style.Widget_Holo_Light_Button)
themedEditText(theme = android.R.style.TextAppearance_Holo_Widget_EditText)
}
包含标签
我们也可以在Anko DSL中包含XML布局文件:
verticalLayout{
include<Button>(R.layout.customButton) {
backgroundColor = Color.RED
}.lparams(width = matchParent) { padding = dip(12) }
}
布局文件的根视图在方括号中指定。
您还可以在{}内部指定特定的类型属性。
verticalLayout{
include<Button>(R.layout.customButton) {
backgroundColor = Color.RED
setOnClickListener{
toast("")}
}.lparams(width = matchParent) { padding = dip(12) }
}
辅助功能
我们可以使用ʻapplyRecursively`函数将属性递归地应用于布局的所有元素。
例:
package net.androidly.androidlyankolayouts
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.widget.Button
import android.widget.TextView
import org.jetbrains.anko.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verticalLayout {
button("Button 1")
textView("TextView 1")
button("Button 2")
textView("TextView 2")
}.applyRecursively { view ->
when (view) {
is Button -> view.backgroundColor = ContextCompat.getColor(ctx, R.color.colorPrimary)
is TextView -> view.textColor = ContextCompat.getColor(ctx, R.color.colorAccent)
}
}
}
}
apply在上面的代码中为不同的视图(按钮和文本视图)递归地设置不同的颜色。
Anko组件
到目前为止,我们已经在"活动"的onCreate函数中直接添加了Anko布局。
使用AnkoComponent接口,我们可以将UI部分与Activity分开。
例:
package net.androidly.androidlyankolayouts
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import org.jetbrains.anko.*
class MainActivity : AppCompatActivity() {
private val textView by lazy {
find<TextView>(R.id.myTextView)
}
lateinit var mainUI: MainActivityUI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainUI = MainActivityUI()
mainUI.setContentView(this)
mainUI.btn.text = "Hello Anko"
textView.text = "Nice AnkoComponent"
}
}
class MainActivityUI : AnkoComponent<MainActivity> {
lateinit var btn: Button
override fun createView(ui: AnkoContext<MainActivity>): View {
return with(ui) {
verticalLayout {
btn = button("Anko Component")
{
id = R.id.myButton
setOnClickListener {
toast("Hello Anko Components")
}
}
textView {
id = R.id.myTextView
}
}
}
}
}
MainActivityUI()。
setContentView(this)用于从Activity中的AnkoComponent类填充布局。
我们可以使用find检索Anko Layout中的小部件。
但这与XML的findViewById相同。

