· 扩展属性,在所有的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