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相同。