Kotlin之编写工具方法

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Kotlin提供的丰富的语法特性给我们提供了无限扩展的可能各种复杂的API经过特定的封装处理之后都能变得简单易用。

文章目录

1.求N个数的最大最小值

两个数比大小这个功能如果我想要获取两个数中较大的那个数除了使用最基本的if语句之外还可以借助Kotlin内置的max函数如下所示

val a=10
val b=15
val larger=kotlin.math.max(a,b)

当我们想要在3个数中获取最大的那个数应该怎么写由于max()函数只能接收两个参数因此需要先比较前两个数的大小然后再拿较大的那个数和剩余的数比较写法如下

val a=10
val b=15
val c=5
val larger=kotlin.math.max(max(a,b),c)

3个数中获取最大值就需要使用这种嵌套max()函数的写法了那如果是4个数、5个数呢这个时候我们可以对max()函数的用法进行简化。
Kotlin中的vararg关键字它允许方法接收任意多个同等类型的参数正好满足我们这里的需求那么我们就可以新建一个Max.kt文件并在其中自定义一个max()函数如下所示

fun max(vararg nums:Int):Int{
    var maxNum=Int.MIN_VALUE
    for(num in nums){
        maxNum=kotlin.math.max(maxNum,num)
    }
    return maxNum
    
}

这里max()函数的参数声明中使用了vararg关键字也就是说现在它可以接收任意多个整型参数。接着我们使用了一个maxNum变量来记录所有数的最大值并在一开始将他赋值成了整型的最小值。然后使用for-in循环遍历nums参数列表如果发现当前遍历的数字比maxNum更大就将maxNum的值更新成这个数最终将maxNum返回即可。
这样经过一层的封装之后我们在使用max()函数就会变得更简便比如

val a=10
val b=15
val c=5
val larger=max(a,b,c)

这样就可以摆脱嵌套函数调用的写法不管是求3个数的最大值还是求N个数的最大值只需要不断地给max()函数传入参数就可以了。
但是现在自定义的max()函数有个缺点就是它只能求N个整型数字的最大值如果我还想要求N个浮点型或长整型数字的最大值。其中一个方法就是对max()函数进行重载来接收不同类型的参数但是这中方案实现起来比较繁琐而且有大量的重复代码。我们可以泛型将max()函数修改成接收任意多个实现Comparable接口的参数代码如下所示

fun <T:Comparable<T>> max(vararg nums:T):T{
    if(nums.isEmpty()){
        throw RuntimeException("params can not be empty")
    }
    var maxNum=nums[0]
    for(num in nums){
        if(num>maxNum){
            maxNum=num
        }
    }
    return maxNum
}

可以看到这里将泛型T的上界指定成了Comparable< T >那么参数T就必然是Comparable< T >的子类型了。接下来我们判断nums参数列表是否为空如果为空的话就主动抛出一个异常提醒调用者max()函数必须传入参数紧接着将maxNum的值赋值成nums参数列表中第一个参数的值然后同样是遍历参数列表如果发现了更大的值就对maxNum进行更新。
经过这样修改之后我们可以灵活地使用max()函数比如说求3个浮点型数字的最大值

fun main(){
    val a=3.5
    val b=3.8
    val c=4.1
    val larger= max(a,b,c)
    println(larger)
}

2.简化Toast的用法

首先回顾一下Toast的标准用法如果想要在界面上弹出一段文字提示需要这样写

Toast.makeText(context,"This is Toast",Toast.LENGTH_SHORT).show()

Toast的makeText()方法接收3个参数第一个参数是Toast显示的上下文环境第二个参数是Toast显示的内容需要由调用方进行指定可以传入字符串和字符串资源id两种类型第三个参数是Toast显示的时长只支持Toast.LENGTH_SHORT和Toast.LENGTH_LONG这两种值。
那么我们可以String类和Int类各添加一个扩展函数并在里面封装弹出Toast的具体逻辑。这样以后每次想要弹出Toast提示时只需要调用它们的扩展函数就可以了。

fun String.showToast(context:Context){
 Toast.makeText(context,this,Toast.LENGTH_SHORT).show()
}
fun Int.showToast(context:Context){
 Toast.makeText(context,this,Toast.LENGTH_SHORT).show()
}

这里分别给String类和Int类新增一个showToast()函数并让它们都接收一个Context参数。然后在函数的内部我们仍然使用了Toast的原生API用法只是将弹出内容改为this另外将Toast的显示时长固定设置成Toast.LENGTH_SHORT。
现在同样是弹出一段文字提醒就可以这么写

"This is Toast".showToast(context)

如果想弹出一个定义在strings.xml中的字符串资源写法如下

R.String.app_name.showToast(context)

这两种写法分别调用的就是我们刚才的String类和Int类中添加的showToast()扩展函数。
还可以对Toast的显示时长进行动态指定我们给函数设定默认值功能这样就可以在不增加showToast()函数使用复杂度的情况下又让它可以支持动态指定显示时长了。

fun String.showToast(context:Context,duration:Int=Toast.LENGTH_SHORT){
 Toast.makeText(context,this,duration).show()
}
fun Int.showToast(context:Context,duration:Int=Toast.LENGTH_SHORT){
 Toast.makeText(context,this,duration).show()
}

我们给showToast()函数增加一个显示时长参数但同时也给它指定了一个默认值。这样我们之前所使用的showToast()函数的写法将完全不受影响默认会使用Toast.LENGTH_SHORT类型的显示时长。如果想使用Toast.LENGTH_LONG的显示时长可以这样写

  "This is Toast".showToast(context,Toast.LENGTH_LONG)

3.简化Snackbar的用法

Snackbar控件和Toast的用法基本相似但是又比Toast稍微复杂一些

snackbar.make(view,"This is Snackbar",Snackbar.LENGTH_SHORT)
.setAction("Action"){
//处理具体的逻辑
}
.show()

可以看到Snackbar中make()方法的第一个参数是View而Toast中makeText()方法的第一个参数是Context另外Snackbar还可以调用setAction()方法来设置一个额外的点击事件。
由于make()方法接收一个View参数Snackbar会使用这个View自动查找最外层的布局用于展示Snackbar。因此我们就可以给View类添加一个扩展函数并在里面封装显示Snackbar的具体逻辑。新建一个Snackbar.kt文件编写如下代码

fun View.showSnackbar(text:String,duration:Int=Snackbar.LENGTH_SHORT){
Snackbar.make(this,text,duration).show()
}
fun View.showSnackbar(resId:Int,duration:Int=Snackbar.LENGTH_SHORT){
Snackbar.make(this,resId,duration).show()
}

我们将扩展函数添加到View类当中并在参数列表上声明了Snackbar要显示的内容以及显示的时长。
想要使用Snackbar显示一段文本提示只需要这样写就可以了

view.showSnackbar("This is Snackbar")

我们还可以让showSnackbar()函数再额外接收一个函数类型参数以此来实现Snackbar的完整功能。

fun View.showSnackbar(text:String,actionText:String?=null,duration:Int=Snackbar.LENGTH_SHORT
,block:(()->Unit)?=null
){
    val snackbar=Snackbar.make(this,text,duration)
    if(actionText!=null&&block!=null){
        snackbar.setAction(actionText){
            block()
        }
    }
    snackbar.show()
}
fun View.showSnackbar(resId:Int,actionResId:Int?=null,duration:Int=Snackbar.LENGTH_SHORT
                      ,block:(()->Unit)?=null
){
    val snackbar=Snackbar.make(this,resId,duration)
    if(actionResId!=null&&block!=null){
        snackbar.setAction(actionResId){
            block()
        }
    }
    snackbar.show()
}

可以看到我们给两个showSnackbar()函数都增加了一个函数类型参数并且还增加了一个用于传递给setAction()方法的字符串或字符串资源id。这里我们将需要新增的两个参数都设置成了可空类型并将默认值都设置成空然后只有当两个参数都不为空的时候我们才去调用Snackbar的setAction()方法来设置额外的点击事件。如果触发了点击事件只需要调用函数类型参数将事件传递给外部的Lambda表达式。

  view.showSnackbar("This is Snackbar","Action"){
            //处理具体逻辑            
        }
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6