您的位置:首页 > 移动开发 > Android开发

Kotlin for Android - 实战记录<一>

2017-06-23 16:47 330 查看
· 扩展属性,在所有的Context及Context的子类中都可以直接 使用
app
属性,且是自定义的Application不需要再强转

/*扩展属性*/
var Context.app: KotlinApplication
get() {
return applicationContext as KotlinApplication
}
set(value) {
app = value
}


· 在项目任何位置都能轻松拿到app实例,不需要强转。

总共写了四个方法,因为在Activity,View,Fragment中都可以通过context直接拿到,当没有context的时候可以通过反射拿到。

fun Activity.getApp(): KotlinApplication = app
fun View.getApp(): KotlinApplication = context.app
fun Fragment.getApp(): KotlinApplication = context.app

fun Any.getAppNoContext(): KotlinApplication {
try {
val application = Class.forName("android.app.AppGlobals").getMethod("getInitialApplication").invoke(null) as Application
return application as KotlinApplication
} catch (e: Exception) {
return KotlinApplication()
}
}


有了以上代码,在Activity,View,Fragment直接
getApp()
就能够拿到自定义的application实例。

其他任意类中也可以通过
getAppNoContext()
直接拿到自定义的application实例。

· 在任意类中,没有context时,获取SharedPreference

fun Any.getSpNoContext(): SharedPreferences {
return getAppNoContext().getSharedPreferences("default", Context.MODE_PRIVATE)
}


· 在Activity中 setContentView(R.layout.activity_xx)之后,可以直接使用布局文件中的id作为控件使用,不需要再findViewById了,比ButterKnife还要好用。

但是在Fragment中,就没有那么轻松了,如果在onCreateView中直接使用布局文件中的id,在运行时会报错。

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflaterView(inflater, R.layout.fragment_xx, null)
//在此处直接使用fragment_xx 里面的id来用,运行时会报错。
return view
}


解决办法1:使用view.控件id,这样可以解决问题,需要导入

import kotlinx.android.synthetic.main.fragment_xx.view.*


并且每次使用都需要用
view.


解决办法2:与方法1基本一致,需要导入

import kotlinx.android.synthetic.main.fragment_xx.view.*


然后使用with关键字,可以省去每次都用
view.
的麻烦。

with(view) {
tv_title.text = "hello,kotlin fragment"
tv_title2.text = "hello,kotlin fragment"
tv_title3.text = "hello,kotlin fragment"
}


解决办法3:直接在onViewCreated中去初始化事件,则不会报错。

· 在项目中常常需要根据editText中的内容变化来做一些事情,在java中我们直接
addTextChangeListener
,在kollin中我们可以写一个简单的扩展函数来让监听editText内容变化着一操作变的更加简单。

先看java代码:

et_test.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d(TAG, "s:" + s);
}

@Override
public void afterTextChanged(Editable s) {

}
});


即使我们对TextWatcher进行简单封装,调用的时候也还是有不少代码,不简洁。而且还需要新建类。

在kotlin中,我们可以通过添加一个扩展函数,让一切变得简单而舒服。

fun EditText.setTextChangeListener(body: (key: String) -> Unit) {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
body(s.toString())
}
})
}


有了上面这段扩展函数,在需要监听editText的内容变化时,只需要一行代码就搞定。

et_key.setTextChangeListener {
Log.d(TAG, "s:" + it);
}


是不是简洁了很多。

· 在项目中,我们常常要用到很多Dialog,Dialog中往往有很多重复的代码,我们可以通过创建一个Dialog模板,来简化Dialog的创建。

先看一个简单的java代码弹出自定义Dialog。

private void showConfigDialog() {
final AlertDialog dialog = new AlertDialog.Builder(getMContext()).create();
dialog.show();
dialog.setContentView(R.layout.dialog_log_config);
Window window = dialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.x = 0;
lp.y = -300;
//不加这句Dialog中EditText无法编辑
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.setCanceledOnTouchOutside(false);

final EditText et_param = (EditText) dialog.findViewById(R.id.et_param);
final EditText et_url = (EditText) dialog.findViewById(R.id.et_url);
Button btn_confirm = (Button) dialog.findViewById(R.id.btn_confirm);
btn_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println(et_param.getText().toString());
System.out.println(et_url.getText().toString());
dialog.dismiss();
}
});
}


以上代码定义了一个自定义布局的dialog,然后对dialog中的控件,进行一些事件操作。也许你的Dialog初始化操作有更多可复用的代码,需要复用的设置直接写在扩展函数里面,可复用操作越少灵活性相对就会高一点,以下是一个简单的dialog的扩展函数。

// AlertDialog的模板
fun Activity.showLayoutDialog(init: AlertDialog.() -> Unit): AlertDialog {
val view = AlertDialog.Builder(this).create()
view.show()
view.init()
val window = view.window
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
return view
}

var AlertDialog.removeY: Int
get() {
val window = window
val lp = window.attributes
return lp.y
}
set(value) {
val window = window
val lp = window.attributes
lp.y = value
}

fun Fragment.showLayoutDialog(init: AlertDialog.() -> Unit): AlertDialog {
return activity.showLayoutDialog { init() }
}


有了以上三段简短的代码,我们在activity和fragment中都可以使用更少的代码去显示一个自定义布局的Dialog,接下来我们看看,如何使用这个Dialog模板,完成上面java代码的工作。

private fun showConfigDialog() {
val dialog = showLayoutDialog {
setContentView(R.layout.dialog_log_config)
setCanceledOnTouchOutside(false)
removeY = -300
}
with(dialog) {
btn_confirm.setOnClickListener {
System.out.println(et_param.text.toString());
System.out.println(et_url.text.toString());
dismiss()
}
}
}


省略了一些通用设置,看着比较清晰,而且不用findViewById了。

文章内容如有错误欢迎指正,对本文内容有任何疑问欢迎加群讨论:283272067
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android kotlin