Skip to content

ActivityExtensions

燒餅 edited this page Jun 13, 2017 · 3 revisions

ActivityExtensions 为使用 Android Activity 组件时提供更多的便利。

安全使用高版本 Android API

有些 Android API 在不同系统版本的调用方法、传参会有所不同,通常我们需要检查 Build.VERSION.SDK_INT 是否达到要求。

本扩展提供一个简短的判断写法:

ifSupportSDK(Build.VERSION_CODES.LOLLIPOP) {
    newMethod()
} ?: run { // 可选,当达不到要求时会执行 run 区块的代码
    oldMethod()
}

安全执行需要应用权限的代码

Android 6.0 开始引入了更完善的权限控制,可以由用户决定是否允许应用使用各项权限,一般情况下应用需要先获取许可之后才可以访问相关数据。

与其它第三方的权限处理 Library 相比较,Kotlinyan 提供了更简洁且完整的权限处理方式。

在这里举一个需要用到写入内部储存的权限的例子:

执行

// 指定要获取的权限
runWithPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) {
	// 应用已经拥有权限许可,可以执行相关代码
	toast("Permission granted")
	saveFile(context, file, data)
} ?: run {
	// 应用获取权限时被拒绝,再次请求前需要解释(“?: run” 区块不可省略,如果不想解释请看下面)
	toast("Permission should show rationale.")
	AlertDialog.Builder(this)
		.setTitle("Permission Denied")
		.setMessage("Without storage permission, you cannot read or save files.")
		// 用户理解并同意应用使用,调用 continueRunWithPermission 方法,如果成功后会执行上面的代码
		.setPositiveButton("Request") {	_, _ -> continueRunWithPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) }
		.setNegativeButton(android.R.string.cancel, {_, _ -> })
		.show()
}

如果你认为被拒绝后再次请求时不需要向用户解释则可以使用:

runWithPermissionNoRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE) {
	// 应用已经拥有权限许可,可以执行相关代码
	toast("Permission granted")
	saveFile(context, file, data)
}

Q: 什么时候应用会向用户解释?

A: 根据 Android 权限控制设计,用户曾拒绝应用请求权限,但没有勾选不再询问,下一次应用请求的时候则会进行解释。

处理成功、拒绝的返回结果

如果不复写 onRequestPermissionsResult 方法,Activity 不能正确收到授权对话框的结果,上面的执行的代码也不能在获得权限后即时生效,

这时候需要用到扩展提供的 handleOnRequestPermissionsResult 方法:

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
	super.onRequestPermissionsResult(requestCode, permissions, grantResults)
	handleOnRequestPermissionsResult(requestCode, permissions, grantResults) {
		// 某个权限被拒绝了,需要做出相关响应
		deniedPermission -> toast("onPermissionDenied: $deniedPermission")
	}
}

给 MenuItem 图标上色

Toolbar 文本颜色会跟随主题设定生效,但 MenuItem 有时不会生效,而且 XML 中也没有提供 tint 属性。

则可以在菜单创建完毕后,调用 Menu.tintItemsColor(color : Int) 或者对某个 MenuItem 调用 tintColor(color : Int)

启用透明状态栏

onCreate 时调用 initTransparentStatusBar() 可启用透明状态栏,不提供布局调整,请自行学习。

创建 AlertDialog

利用 Kotlin 特性,使用更简洁的方式代替 Builder 模式的链式调用创建 AlertDialog。

原来在 Java 上需要这样写:

new AlertDialog.Builder(this)
               .setTitle(R.id.dialog_title)
               .setMessage(R.id.dialog_message)
               .setCancelable(true)
               .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                         hello();
                    }
               })
               .show();

引入 Kotlinyan 后的 Kotlin 写法是:

buildAlertDialog {
    titleRes = R.id.dialog_title
    messageRes = R.id.dialog_message
    isCancelable = true
    positiveButton(android.R.string.ok) { _, _ ->
        hello()
    }
    // 这里还可以继续调用 AlertDialog.Builder 自带的函数或者 Kotlinyan 扩展提供的参数
}.show()

Kotlinyan 扩展后 AlertDialog.Builder 新增的参数:

  • title 标题 (String) / titleRes 标题资源 ID (Int)
  • message 消息文本 (String) / messageRes 消息文本资源 ID (Int)
  • positiveButton 函数 设置确认按钮事件
  • negativeButton 函数 设置取消按钮事件
  • neutralButton 函数 设置中立按钮事件
  • view 自定义布局 (View) / viewRes 自定义布局资源 ID (Int)
  • customTitle 自定义标题布局 (View)
  • icon 图标 (Drawable) / iconRes 图表资源 ID (Int)
  • iconAttribute 图标 attr (Int)
  • onCancel 取消事件 ((DialogInterface) -> Unit)
  • onDismiss 关闭事件 ((DialogInterface) -> Unit)
  • onKey 按键回调 (DialogInterface.OnKeyListener)
  • onItemSelected 选项事件 (AdapterView.OnItemSelectedListener)

如果你想使用 AppCompat v7 包里面的 android.support.v7.app.AlertDialog,请引入 :kotlinyan-appcompat-supportAppCompatExtensions,使用 buildV7AlertDialog { ... } 代替 buildAlertDialog { ... }