学习 Kotlin 应该都或多或少听过 Anko 这个开源库。
使用 Anko 来构建界面会更加简单、快捷。
毕竟以往的布局都是要从 XML 中解析出来,然后再到 LayoutInfalter 里面通过 Constructor.newInstance 反射创建出来的。而 Anko 则是直接创建 View,用代码构建布局,省去了解析 XML 的时间。
添加依赖
Anko 的 Github 仓库是:https://github.com/Kotlin/anko
。
在 Github 仓库的 README 上关于如何添加依赖已经写的很详细了,把要添加的选择性复制粘贴就好了。
Anko 包括四个部分内容:
- Anko Commons
- 轻量级的一些帮助类,比如 intent,dialog,logging 等等,其实就是对安卓一些类:Activity、Fragment、Intent 等添加扩展函数。
- Anko Layouts
- 动态布局用的最主要的库,将许多 Android 的控件 View 转换成了 Anko 加载的形式。
- 由于 Android 还有其他的控件库,因此 Anko 也对那些库进行了拓展支持,可以选择添加对应的依赖库。
- 当然,还可以根据需要对自定义 View 进行改造,让它们也支持 Anko 加载的形式。
- Anko SQLite
- 用于 Android SQLite 数据库的查询的库
- Anko Coroutines
- 基于
kotlinx.coroutines
协程的一个工具库。
- 基于
创建简单布局
使用 Anko 创建布局很简单:
1class AnkoActivity : AppCompatActivity() {
2 override fun onCreate(savedInstanceState: Bundle?) {
3 super.onCreate(savedInstanceState)
4 relativeLayout {
5 button("button in center") {
6 textSize = sp(18).toFloat()
7 onClick {
8 longToast("you click button")
9 }
10 }.lparams {
11 centerInParent()
12 }
13 }
14 }
15}
效果如下:
在 relativeLayout
代码块里我们构建了当前的界面,并把它应用到了 Activity 中。
在这里,并没有使用熟悉的 setContentView 方法,这是因为 Anko 会自动将布局界面 View 设置到 Activity 中。
relativeLayout
代码块就是 Anko 的主要使用方法。
relativeLayout
作为一个容器,在里面添加了一个 button
,button
控件的第一个大括号里设置了它的一些属性和事件,在 lparams
大括号里设置了它在相对于容器的一些参数。
就是这样简单的写法完成了界面布局,如同写 xml 文件一样,只要在父容器里面按照排列写好子控件的参数和位置就好。
多实践几次就可以熟练这种写法,通过 Anko 来创建一个登陆界面:
1 verticalLayout {
2 padding = dip(8)
3 val account = textView("account") {
4 id = R.id.account_text
5 textSize = sp(12).toFloat()
6 // 设置自己的属性
7 }.lparams() {
8 // 设置布局的参数
9 }
10 var name = editText() // 也可以什么都不设置,使用默认的设置
11 textView("password") {
12 id = R.id.password_text
13 onClick {
14 account.setText("change account")
15 }
16 }
17 var pwd = editText {
18 hint = "input"
19 }.lparams(
20 width = dip(100),
21 height = ViewGroup.LayoutParams.WRAP_CONTENT
22 )
23 button("login") {
24 onClick {
25 if (name.text.toString().equals("name")
26 && pwd.text.toString().equals("pwd")) {
27 longToast("login....")
28 } else {
29 longToast("login failed")
30 }
31 }
32 }
33 }
效果如下:
使用 AnkoComponent 接口创建界面
除了直接在 Activity 里面写布局,还可以使用 AnkoComponent 接口创建布局,这样就可以将界面代码和 Activity 的代码分离了。
1class MyActivity : AppCompatActivity() {
2 override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
3 super.onCreate(savedInstanceState, persistentState)
4 MyActivityUI().setContentView(this)
5 }
6}
7
8class MyActivityUI : AnkoComponent<MyActivity> {
9 override fun createView(ui: AnkoContext<MyActivity>) = with(ui) {
10 verticalLayout {
11 val name = editText()
12 button("Say Hello") {
13 onClick { ctx.toast("Hello, ${name.text}!") }
14 }
15 }
16 }
17}
需要创建我们的界面类,实现 AnkoComponent
接口,在 createView
方法中返回我们的界面。
最后在 setContentView
方法中实际调用的也是 createView
方法,返回界面布局,然后再由上面提到的,Anko 会自动把布局填充到 Activity 中。
这里使用到了 Kotlin with
的语法糖,使用 with
,则返回的是最后一行的内容,正好 verticalLayout 就是最后一行的内容。
也可以把它转换一下,使用 apply
的语法糖,最后返回的调用该方法的对象,再接着返回该对象的 view 就好了。
1class MyActivityUI : AnkoComponent<MyActivity> {
2 override fun createView(ui: AnkoContext<AnkoActivity>) = ui.apply {
3 verticalLayout {
4 val name = editText()
5 button("Say Hello") {
6 onClick { ctx.toast("Hello, ${name.text}!") }
7 }
8 }
9 }.view
10}
Fragment 中加载界面
在 Fragment 中添加界面稍有不同。
创建 Activity,将 Fragment 添加上来。
1class AnkoFragmentActivity : AppCompatActivity() {
2 override fun onCreate(savedInstanceState: Bundle?) {
3 super.onCreate(savedInstanceState)
4 linearLayout {
5 id = R.id.fragment_id
6 supportFragmentManager.beginTransaction().replace(id, AnkoFragment.newInstance()).commit()
7 }
8 }
9}
1class AnkoFragment : Fragment() {
2
3 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
4// return inflater.inflate(R.layout.fragment_anko, container, false)
5 return UI {
6 verticalLayout {
7 editText()
8 button("OK")
9 }
10 }.view
11 }
12
13 companion object {
14 fun newInstance(): AnkoFragment {
15 return AnkoFragment()
16 }
17 }
18}
在 Fragment 的 onCreateView 方法中不在使用 inflater 来加载布局,而是直接使用 UI
函数来完成,返回最后的 View 即可。其中 UI
也是对 Fragment 的一个拓展函数。
自定义 View 的加载
除了 Anko 自带以及支持的控件之外,还可以让自定义的 View 也支持 Anko 的加载方式,在 Anko 的代码块中去更改自定义 View 的设置属性。
比如,自定义 View ,绘制一个矩形:
1public class RectangleView extends View {
2 public int size ;
3 public Paint mPaint;
4 public RectangleView(Context context) {
5 super(context);
6 mPaint = new Paint();
7 mPaint.setColor(Color.RED);
8 mPaint.setAntiAlias(true);
9 mPaint.setStrokeWidth(2);
10 mPaint.setStyle(Paint.Style.STROKE);
11 }
12 @Override
13 protected void onDraw(Canvas canvas) {
14 super.onDraw(canvas);
15 setBackgroundColor(Color.BLUE);
16 canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, size, mPaint);
17 }
18}
其中,size 变量就是要改变的属性,它控制着圆的半径。
让自定义 View 支持 Anko 的加载方式,还需要添加如下的拓展函数:
1inline fun ViewManager.rectangleView(init: RectangleView.() -> Unit): RectangleView {
2 return ankoView({ RectangleView(it) }, theme = 0, init = init)
3}
由该拓展函数来返回我们的 Rectangle View ,至于这其中是如何实现的,暂时不做深究,下篇文章再来探讨。
最后就可以像使用其他控件一样来添加到布局中了。
1 //加载自定义的 View
2 relativeLayout {
3 var view = rectangleView {
4 id = R.id.custom_view_id
5 size = 300 // 自定义 View 的属性设置
6 }.lparams {
7 width = ViewGroup.LayoutParams.MATCH_PARENT
8 height = dip(200)
9 centerInParent()
10 }
11
12 button("change size") {
13 onClick {
14 view.size = Random().nextInt(200) + 100
15 view.invalidate()
16 }
17 }.lparams {
18 below(view)
19 centerHorizontally()
20 }
21 }
效果如下:
点击按键来更改圆的半径大小。
Anko 配合 RecyclerView 的使用
使用 Anko 来构建一个下拉刷新的 RecyclerView 布局。
写法依旧简单:
1 swipeRefreshLayout {
2 setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN)
3 onRefresh {
4 mainHandler.postDelayed(Runnable {
5 isRefreshing = false
6 }, 3000)
7 }
8 recyclerView {
9 layoutManager = LinearLayoutManager(SampleApp.mContext)
10 setHasFixedSize(true)
11 adapter = Adapter(dataList)
12 }
13 }
直接在 recyclerView 布局里面设置好相应的 LayoutManager 和 Adapter 就好了。
同时还能够在 swipeRefreshLayout 里面处理刷新的事件,在三秒后更改刷新状态,从而停止刷新就好了。
源码参考 Github 地址:https://github.com/glumes/AndroidKotlinSample
不足
Anko 好是好,但是依旧不够完美。
在 XML 中能够设置的控件属性更多,更精确的控制布局状态,而 Anko 在构建简单界面的时候才显得快速、便捷。
而且 Anko 支持的控件有限,加载自定义的控件还得添加额外的代码,在更复杂的应用中应该不太会广泛的使用。
参考
1、https://github.com/Kotlin/anko/wiki/Anko-Layouts
原创文章,转载请注明来源: Kotlin 使用 Anko 布局那些事
相关文章
留言