下面我们来完成这个添加日程的界面。
我们采用Fragment来实现。首先新建一个TodoEditFragment继承Fragment() :
class TodoEditFragment : Fragment() {
val realm: Realm = Realm.getDefaultInstance()
var todo: Todo? = null
companion object {
val TODO_ID_KEY: String = "todo_id_key"
fun newInstance(id: String): TodoEditFragment {
var args: Bundle = Bundle()
args.putString(TODO_ID_KEY, id)
var todoEditFragment: TodoEditFragment = newInstance()
todoEditFragment.arguments = args
return todoEditFragment
}
fun newInstance(): TodoEditFragment {
return TodoEditFragment()
}
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return UI {
// AnkoContext
verticalLayout {
padding = dip(30)
var title = editText {
// editText 视图
id = R.id.todo_title
hintResource = R.string.title_hint
}
var content = editText {
id = R.id.todo_content
height = 400
hintResource = R.string.content_hint
}
button {
// button 视图
id = R.id.todo_add
textResource = R.string.add_todo
textColor = Color.WHITE
setBackgroundColor(Color.DKGRAY)
onClick { _ -> createTodoFrom(title, content) }
}
}
}.view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (arguments != null && arguments.containsKey(TODO_ID_KEY)) {
val todoId = arguments.getString(TODO_ID_KEY)
todo = realm.where(Todo::class.java).equalTo("id", todoId).findFirst()
val todoTitle = find<EditText>(R.id.todo_title)
todoTitle.setText(todo?.title)
val todoContent = find<EditText>(R.id.todo_content)
todoContent.setText(todo?.content)
val add = find<Button>(R.id.todo_add)
add.setText(R.string.save)
}
}
override fun onDestroy() {
super.onDestroy()
realm.close()
}
/**
* 新增待办事项,存入Realm数据库
*
* @param title the title edit text.
* @param todoContent the content edit text.
*/
private fun createTodoFrom(title: EditText, todoContent: EditText) {
realm.beginTransaction()
// Either update the edited object or create a new one.
var t = todo ?: realm.createObject(Todo::class.java)
t.id = todo?.id ?: UUID.randomUUID().toString()
t.title = title.text.toString()
t.content = todoContent.text.toString()
realm.commitTransaction()
activity.supportFragmentManager.popBackStack()
}
}
其中,我们重点讲下 Anko 的 UI 布局部分的代码。
return UI {
// AnkoContext
verticalLayout {
padding = dip(30)
var title = editText {
// editText 视图
id = R.id.todo_title
hintResource = R.string.title_hint
}
var content = editText {
id = R.id.todo_content
height = 400
hintResource = R.string.content_hint
}
button {
// button 视图
id = R.id.todo_add
textResource = R.string.add_todo
textColor = Color.WHITE
setBackgroundColor(Color.DKGRAY)
onClick { _ -> createTodoFrom(title, content) }
}
}
}.view
我们使用 Kotlin 的代码 Anko DSL 创建了一个垂直方向的线性布局(用代码写配置写布局要比 XML 灵活方便多了)。 其中 UI 函数
fun Fragment.UI(init: AnkoContext<Fragment>.() -> Unit) = createAnkoContext(activity, init)
是Fragment的扩展函数,它接收一个函数
init: AnkoContext<Fragment>.() -> Unit
init 的入参是AnkoContext类型。
而verticalLayout函数则是ViewManager的内联扩展函数。
inline fun ViewManager.verticalLayout(init: _LinearLayout.() -> Unit): LinearLayout {
return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, init)
}
从这些例子我们可以看出 Kotlin 的函数扩展功能相当实用,尤其在 DSL 中用的非常广泛。
在 verticalLayout 代码段内部,创建了三个Android的控件 - 两个 editText 视图和一个 button 视图。这里视图的属性都在一行里面设置好了。
padding = dip(30)
var title = editText {
// editText 视图
id = R.id.todo_title
hintResource = R.string.title_hint
}
var content = editText {
id = R.id.todo_content
height = 400
hintResource = R.string.content_hint
}
button {
// button 视图
id = R.id.todo_add
textResource = R.string.add_todo
textColor = Color.WHITE
setBackgroundColor(Color.DKGRAY)
onClick { _ -> createTodoFrom(title, content) }
}
这样的视图文件要比 XML 优雅许多了,XML 的配置有时候让人看了就心生烦恼。我们可以看下按钮控件定义的地方。按钮有一个点击监听函数是定义在视图定义文件里面的。在定义按钮之前,有两个参数 title 和 content 的方法 createTodoFrom 已经被调用了。最后,通过在 AnkoContext (UI 类)上调用 view 属性UI {...}.view来返回视图。
这里的 ids 被设置为 R.id.<id_name>。这些 ids 需要手工在一个加做 ids.xml 的文件里创建,这个文件放在 app/src/main/res/values/ids.xml。如果这个文件不存在就创建它。文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="todo_title" type="id" />
<item name="todo_content" type="id" />
<item name="todo_add" type="id" />
</resources>
这个 ids.xml 文件定义了所有能够被代码引用到的各种视图的 ids。