Android Anko布局

时间:2020-02-23 14:28:45  来源:igfitidea点击:

在本教程中,我们将讨论和实现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相同。