现在 kotlin 用的较多的领域,应该是 android 应用开发了吧。最近开了个小差,有人买彩票不想自己预测了,也不想现场用彩票店的机器出号,太费事儿。就用 kotlin 写个手机 apk 给他。要求也不高,只要随机出数字就行。
需求搞清楚了,可以开工了。
首先要确定,他可能还要给自己的旧手机也装上,为求万千稳妥,API 的最小版本选择了 15。
之后选择空的 Activity 就开场了。
系统默认给出一个界面。
我们不理他,因为,还计划着以后再继续在这个项目中万一增加其他小工具呢。
所以新建一个package,取名就用汉语拼音吧。 CaiPiao
然后在这个 package 下新建一个空活动(Empty Activity)
下面,我们要做的第一件事,就是让第一个活动(MainActivity)被应用启动后,直接跳转到我们这个 CaiPiao 下的空活动来。
打开 MainActivity ,添加代码。先写一个函数 OpenCaiPiao ,在函数内实现需要的功能。
//跳转到彩票界面
fun OpenCaiPiao(){//我要顺顺的来
val intent = Intent()
intent.setClass(this, CaipiaoActivity::class.java)
startActivity(intent)
}
把它放在 class MainActivity 内,并在 onCreate 函数内添加调用语句 OpenCaiPiao()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
OpenCaiPiao()
}
这时候,我们的注意力就可以专注到真正的业务模块中了。
在 res>layout 中打开 activity_caipiao.xml,拖拽三个 button 和 两个 textview。
一个 button 对应“双色球”
一个 button 对应“大乐透”
一个 button 对应“清除”功能
一个 textview 对应给出的彩票号码
一个 textview 对应给出彩票号码的时间
现在流行最新的布局方式,也是默认的ConstraintLayout。我就用这种了。
这个布局中,为了保持“随机号码”和“出号时间”的左对齐,只设定了上边和左边的距离,它们字号不同,控制了右边距离的话,文字内容发生改变,会有对不齐的情况发生。
双色球和大乐透两个按钮,略有不同,双色球设置了上、左、右到边沿,而大乐透的左边是指在双色球按钮的右侧控键上。这样,两个按钮的位置就相对固定了。不论横屏还是竖屏都不会变。
相似的“清除按钮”的上边constraint也控制到双色球按钮的下侧控键上,这样“清除按钮”和“双色球按钮”的相对位置也就保持不变了。
下面就该填写这个Activity中的代码了。
界面中可以直接操作就是这三个按钮了,先在 CaiPiaoActivity.kt 的 OnCreate 中增加这三个按钮的 OnClick 事件的监听。
//双色球
btnGetShuangSeQiu.setOnClickListener {
}
//大乐透
btnDaLeTou.setOnClickListener {
}
//清除取消
btnCancel.setOnClickListener {
}
随机出彩票号码,那么核心功能是随机了。先写一个在指定的范围内出随机数字的函数出来。
/**
* 取得min到max之间的随机整数(不包含max)
* @min 最小取值
* @max 最大取值边界(此值不取)
* */
fun cofoxRandom(min: Int = 0, max: Int): Int {
var t_min = min
var t_max = max
if (t_min > t_max) {
var temp: Int
temp = t_min
t_min = t_max
t_max = temp
}
var random = (Math.floor(Math.random() * (t_max - t_min))).toInt() + t_min
return random
}
这里要注意这个注释的写法
/**
*
* */
这样标准的写法能够被 IDE 准确的识别,才能有下面的效果。
我们要写双色球的随机出号了
首先定义一个整数数组,先都赋值为 0 好了。
var ints = intArrayOf(0, 0, 0, 0, 0, 0, 0)
当然你也可以这样写
var ints = Array(7,{0})
第一种写法,是方便直接把所有的数组元素(不同值)都写进去。
第二种写法,更简洁一些,适合初始化时候都赋相同值的情况。
建立了数组,就该把随机数字填写进去了。
for (i in 1..6) {
ints[i - 1] = cofoxRandom(1, 34)
}
双色球是 6 + 1 的出球方式。我们先出 6 个红球,所以是 1..6。
由于 cofoxRandom 函数的max值是不包含在可选范围内的,所以1-33个红球号码,我们需要的参数是(1, 34)
至于 ints[i-1],是因为,数组的下标是从 0 开始的。
这样就可以把 6 个球号得到了。
但是,还有个问题,数字是乱的。我们需要给这 6 个数字排序。这也是一个很常见的需求。
//排序前六位,第七位当临时存储位
for (i in ints.indices) {
for (j in ints.indices - i) {
if (j < ints.size - 1) {
if (ints[j] > ints[j + 1]) {
ints[ints.size - 1] = ints[j + 1]
ints[j + 1] = ints[j]
ints[j] = ints[ints.size - 1]
}
}
}
}
这里,我们为了节省内存,就不再另外加变量了。先利用那个蓝色号码的位置,作为排序时的临时存储位。每次循环,都把较大的一个数字往后移动一位。于是,在第二层循环,每次循环都可以少循环一个已经确定了的较大数字。这就是
for (i in ints.indices) {
for (j in ints.indices - i) {
这个的来由。顺便说一下,indices是取得ints下标的意思。这样i和j就能得到当前循环的具体下标了。
循环完,一个由小到大排列好的数组就出来了。
如果想完美,还有一个问题要解决,重复数字。随机给出的数字经常是重复的。只要再加一个逻辑,当新的随机数出来后,判断一下在数组中是否存在这个数字了即可。如果存在,当前循环内再次取得随机数,直到取得了不在数组中的数字为止。
我们可以用 for 循环嵌套 while 循环实现。我们来修改刚才那个 随机数字填写 的 for 循环。
for (i in 1..6) {
// ints[i - 1] = cofoxRandom(1, 34)
var temp = cofoxRandom(1, 34)
while (temp in ints){
temp = cofoxRandom(1, 34)
}
ints[i - 1] = temp
}
现在,数组内的号码球数字不会重复了。
双色球还有一个蓝色号码求哦,这个就直接出好了。
ints[ints.size-1] = cofoxRandom(1, 17)//蓝色号码球
数字都出完了。我们还可以来调一调数字格式。因为,有一位数也有两位数嘛,排列总是看起来有点不够整齐。那就一位数的都在左侧补0吧。不仅如此,每个数字之间用逗号(,)分隔开,再把红球和蓝球用短横线(-)分隔开。
//按格式书写
var str = "双色球:"
for (i in ints.indices) {
if (ints[i].toString().length < 2){
str += "0"+ints[i].toString()
}else {
str += ints[i]
}
if (i == ints.size-2){
str += " - "
}else if (i == ints.size -1){
}else{
str += ", "
}
}
好了。重要的代码都写完了。剩下就是把 str 赋值给界面控件了吧?
还可以再多做一点事情。不要把这么多的代码都放进 onCreate ,独立出一个函数来。让代码更整洁。于是,我们可以得到一个“福彩双色球随机猜想出号”函数了。
/**
* 福彩双色球随机猜想出号
* */
fun cofoxShuangSeQiu(ttvw:TextView){
// var ints = intArrayOf(0, 0, 0, 0, 0, 0, 0)
var ints = Array(7,{0})
for (i in 1..6) {
// ints[i - 1] = cofoxRandom(1, 34)
var temp = cofoxRandom(1, 34)
while (temp in ints){
temp = cofoxRandom(1, 34)
}
ints[i - 1] = temp
}
//排序前六位,第七位当临时存储位
for (i in ints.indices) {
for (j in ints.indices - i) {
if (j < ints.size - 1) {
if (ints[j] > ints[j + 1]) {
ints[ints.size - 1] = ints[j + 1]
ints[j + 1] = ints[j]
ints[j] = ints[ints.size - 1]
}
}
}
}
ints[ints.size-1] = cofoxRandom(1, 17)//蓝色号码球
//按格式书写
var str = "双色球:"
for (i in ints.indices) {
if (ints[i].toString().length < 2){
str += "0"+ints[i].toString()
}else {
str += ints[i]
}
if (i == ints.size-2){
str += " - "
}else if (i == ints.size -1){
}else{
str += ", "
}
}
ttvw.text = str
}
而 onCreate 中对这个函数进行调用。
cofoxShuangSeQiu(ttvwRandomNumber)
ttvwRandomNumber 就是 textview 的 id
在界面上为了更友好一些,我们增加了出号时间。现在就是添加这个功能代码的时候了。
/**
* 显示当前出号时间
* */
fun cofoxGetNumberTime(ttvw: TextView){
//出号时间
var ver = android.os.Build.VERSION.SDK_INT
if (ver >= 24){
ttvw.text = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
}else{
val calendar = GregorianCalendar()
ttvw.text = GregorianCalendar().get(Calendar.YEAR).toString() +"-"+ (GregorianCalendar().get(Calendar.MONTH)+1).toString() +"-"+ GregorianCalendar().get(Calendar.DAY_OF_MONTH).toString() +" "+ GregorianCalendar().get(Calendar.HOUR).toString() +":"+ GregorianCalendar().get(Calendar.MINUTE).toString() +":"+ GregorianCalendar().get(Calendar.SECOND).toString()
}
}
好吧,这也是写成了一个函数。并且其中用了两种取得当前时间的方法。因为,我们开始的时候,希望这个应用能支持到 API 15,而最简洁最新的时间获取的写法是从 API 24 之后才开才是支持的。
那么先判断一下当前运行的 android 系统的 API 是哪个版本,然后对症下药。
之后,我们再把调用语句写入 onCreate 中。
//双色球
btnGetShuangSeQiu.setOnClickListener {
cofoxShuangSeQiu(ttvwRandomNumber)
cofoxGetNumberTime(ttvwTime) //出号时间
}
双色球的调用完成了。
大乐透只是稍有不同
大乐透的号码球一共也是 7 个,但是,大乐透的玩法是分前区和后区。是 5 + 2 的结构。所以,在双色球的代码基础上略微修改就可以获得大乐透的写法了。
/**
* 体彩大乐透随机猜想出号
* */
fun cofoxDaLeTou(ttvw:TextView){
// var ints = intArrayOf(0, 0, 0, 0, 0, 0, 0)
var ints = Array(7,{0})
for (i in 1..5) {
// ints[i - 1] = cofoxRandom(1, 36)
var temp = cofoxRandom(1, 36)
while (temp in ints){
temp = cofoxRandom(1, 36)
}
ints[i - 1] = temp
}
//排序前5位,第6位当临时存储位
for (i in ints.indices - 2) {
for (j in ints.indices - i) {
if (j < ints.size - 2) {
if (ints[j] > ints[j + 1]) {
ints[ints.size - 2] = ints[j + 1]
ints[j + 1] = ints[j]
ints[j] = ints[ints.size - 2]
}
}
}
}
ints[ints.size-2] = cofoxRandom(1, 13)//后区号码球1
ints[ints.size-1] = cofoxRandom(1, 13)//后区号码球2
//按格式书写
var str = "大乐透:"
for (i in ints.indices) {
if (ints[i].toString().length < 2){
str += "0"+ints[i].toString()
}else {
str += ints[i]
}
if (i == ints.size-3){
str += " - "
}else if (i == ints.size -1){
}else{
str += ", "
}
}
ttvw.text = str
}
这时候,在 onCreate 中修改大乐透的调用代码就简单多了。
//大乐透
btnDaLeTou.setOnClickListener {
cofoxDaLeTou(ttvwRandomNumber)
cofoxGetNumberTime(ttvwTime) //出号时间
}
还记得我们的“清除”按钮吗?是的,也要在 onCreate 中写上监听代码。
//清除取消
btnCancel.setOnClickListener {
ttvwRandomNumber.text = resources.getString(R.string.txt_cnword_随机号码)
ttvwTime.text = resources.getText(R.string.txt_出号时间)
}
这里的 R.string 是什么?它们资源文件 res>values 下 strings.xml 内的东西。
我们在这里实践了一下编码中对中文变量的支持。呵呵。
编译一下