ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
我们看一下实际项目中常用的例子:Snackbar。几年前,它被添加到Android支持库中,以取代作为用户和应用程序之间的消息传递接口长期服务的Toast。它解决了一些问题并引入了一种全新的外观,基本使用方式如下: ``` Snackbar.make(parentView, message_text, duration) .setAction(action_text, click_listener) .show(); ``` 但是实际中使用它的API会给代码增加不必要的复杂性:**我们不希望每次都定义我们想要显示消息的时间,并且在填充一堆参数后,为什么我们还要额外调用show()?** 著名的开源项目**Anko拥有Snackbar的辅助函数,使其更易于使用并使代码更简洁**: ``` snackbar(parentView, action_text, message_text) { click_listener } ``` 其中一些参数是可选的,所以我们一般这么使用: ``` snackbar(parentView, "message") ``` anko中的snackbar的部分源码如下: ``` inline fun View.snackbar(message: Int, @StringRes actionText: Int, noinline action: (View) -> Unit) = Snackbar .make(this, message, Snackbar.LENGTH_SHORT) .setAction(actionText, action) .apply { show() } ``` 但是这样就够了吗?我们想让它更短,对于大多数情况,我们需要的唯一参数是消息。所以我们的调用方式是: ``` snackbar("message") ``` 因为我们关心的仅仅是在屏幕底部显示我们的消息,所以需要消除视图参数。幸运的是,借助扩展函数,在Activity中获取根视图可以通过使用Anko中的`find (android.R.id. content)`来完成。改良后的Activity的扩展方法如下所示: ``` inline fun Activity.snackbar(message: String) = snackbar(find (R.id.content), message) ``` 除了在Activity中,我们通常还在哪里使用Snackbar呢?**Android UI中还有两个重要的组件:Fragment和View**。在Fragment中,有一个它所在的Activity的引用。所以实现我们的解决方案要容易得多: ``` inline fun Fragment.snackbar(message: String) = snackbar(activity.find (R.id. content), message) ``` 而View并不一定附加在Activity上,我们要做出防御式判断,即:在我们尝试显示Snackbar之前,我们必须确保View的context属性隐藏了一个Activity实例: ``` inline fun View.snackbar(message: String) { val activity = context if (activity is Activity) snackbar(activity.find(android.R.id.content), message) else throw IllegalStateException("视图必须要承载在Activity上.") } ``` 小练习 上述例子结合Anko的`find(R.id)`使用,你是否能够改写为不依赖Anko呢?动手尝试一下吧!