Android安卓实战项目(8)—自行车fitting计算软件(源码在文末🐕🐕🐕)可用于比赛项目或者作业参考中
【bilibili演示地址】 https://www.bilibili.com/video/BV1eu4y1B7yA/?share_source=copy_web&vd_source=b2e9b9ed746acda34f499009647748ed
介绍:
在这个数字化时代,自行车运动在越来越多的人中变得流行。然而,要达到最佳的骑行体验,确保您的自行车尺寸与个人需求相匹配至关重要。为了解决这个问题,我开发了一个自行车骑行风格计算工具应用程序,它可以帮助您找到最适合您的自行车尺寸,并提供更加舒适和高效的骑行体验。
功能和目的:
该应用程序旨在帮助骑行爱好者确定适合自己的自行车尺寸,以获得更好的骑行体验。用户只需要输入脚踏板到坐垫的距离(鸭蛋高度),然后选择骑行风格(休闲、普通、竞赛),应用程序将根据一些计算公式自动计算出坐垫高度、STACK 值和 REACH 值。
工作原理:
- 用户输入鸭蛋高度:用户首先在应用程序中输入他们的鸭蛋高度,即脚踏板到坐垫的距离。
- 选择骑行风格:用户可以从休闲、普通和竞赛中选择一个骑行风格,以适应不同的骑行需求。
- 计算自行车尺寸:应用程序使用输入的鸭蛋高度和所选骑行风格,通过预定义的计算公式来计算出坐垫高度、STACK 值和 REACH 值。
- 显示结果:计算完成后,应用程序将结果显示在界面上,用户可以清楚地了解哪种自行车尺寸最适合他们的需求。
界面和交互:
该应用程序具有简洁直观的用户界面。用户可以在输入框中输入鸭蛋高度,通过单选按钮选择骑行风格,并点击“计算”按钮执行计算操作。计算结果将即时显示在界面上,包括坐垫高度、STACK 值和 REACH 值。
代码结构和关键函数:
该应用程序使用了 Kotlin 语言和 Android 开发框架。主要包含以下几个关键函数:
initView()
:用于初始化界面,设置监听器和初始值。calculateData()
:用于进行数据计算,并将计算结果显示在界面上。calculateSeatHeight()
:计算坐垫高度的函数。calculateStack()
:计算 STACK 值的函数。calculateReach()
:计算 REACH 值的函数。
代码可扩展性:
该应用程序具有很好的可扩展性。您可以根据需要添加更多骑行风格选项或者调整计算公式,以满足不同骑行者的需求。同时,您也可以通过进一步优化界面设计和交互方式,提升用户体验。
总结:
该自行车骑行风格计算工具是一款实用的应用程序,它能够帮助骑行爱好者找到最适合自己的自行车尺寸,从而提高骑行的舒适性和效率。无论是新手还是资深骑手,使用该应用程序都能够获得更好的骑行体验。欢迎您下载并尝试这个实用的自行车骑行风格计算工具,祝您在骑行中获得更多乐趣和成就。
一.项目运行介绍
二.具体实现
MainActivity.java
package io.github.laomao1997.bikefitter
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.RadioGroup
import android.widget.TextView
import androidx.annotation.IntDef
import androidx.appcompat.app.AppCompatActivity
import java.math.BigDecimal
class MainActivity : AppCompatActivity() {
companion object {
/**
* 骑行风格常量 - 休闲
*/
const val TYPE_RELAX = 0
/**
* 骑行风格常量 - 普通
*/
const val TYPE_NORMAL = 1
/**
* 骑行风格常量 - 竞赛
*/
const val TYPE_RACE = 2
}
private lateinit var mEtEggHeight: EditText
private lateinit var mBtnCalculate: Button
private lateinit var mRadioGroup: RadioGroup
private lateinit var mTvSeatHeight: TextView
private lateinit var mTvStackHeight: TextView
private lateinit var mTvReachHeight: TextView
@RidingStyleTypeDef
private var mRidingStyle = TYPE_NORMAL
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
}
private fun initView() {
mEtEggHeight = findViewById(R.id.et_egg_height)
mBtnCalculate = findViewById(R.id.btn_calculate)
mRadioGroup = findViewById(R.id.radio_group)
mTvSeatHeight = findViewById(R.id.tv_seat_height)
mTvStackHeight = findViewById(R.id.tv_stack_height)
mTvReachHeight = findViewById(R.id.tv_reach_height)
//点击软键盘外部,收起软键盘
mEtEggHeight.setOnFocusChangeListener { v, hasFocus ->
if (!hasFocus) {
val manager: InputMethodManager =
applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
manager.hideSoftInputFromWindow(v.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}
}
mBtnCalculate.setOnClickListener {
mEtEggHeight.clearFocus()
calculateData()
}
mRadioGroup.check(R.id.type_normal)
mRadioGroup.setOnCheckedChangeListener { _, checkedId ->
when (checkedId) {
R.id.type_relax -> mRidingStyle = TYPE_RELAX
R.id.type_normal -> mRidingStyle = TYPE_NORMAL
R.id.type_race -> mRidingStyle = TYPE_RACE
}
calculateData()
}
}
@SuppressLint("SetTextI18n")
private fun calculateData() {
val eggHeight = getEggHeight()
val seatHeight = calculateSeatHeight(eggHeight)
val stack = calculateStack(eggHeight)
val reach = calculateReach(stack)
mTvSeatHeight.text = if (seatHeight == 0.0) {
getString(R.string.double_line)
} else {
BigDecimal(seatHeight).setScale(1, BigDecimal.ROUND_HALF_UP).toString()
}
mTvStackHeight.text = if (stack == 0.0) {
getString(R.string.double_line)
} else {
BigDecimal(stack).setScale(1, BigDecimal.ROUND_HALF_UP).toString()
}
mTvReachHeight.text = if (reach == 0.0) {
getString(R.string.double_line)
} else {
BigDecimal(reach).setScale(1, BigDecimal.ROUND_HALF_UP).toString()
}
}
private fun getEggHeight(): Int {
val eggHeightText: String = mEtEggHeight.text.toString()
return try {
eggHeightText.toInt()
} catch (e: Exception) {
0
}
}
/**
* 计算坐垫高度
*/
private fun calculateSeatHeight(eggHeight: Int): Double {
if (eggHeight <= 0) return 0.0
return eggHeight * Constant.SEAT_HEIGHT_RATIO
}
/**
* 计算 STACK 值
*/
private fun calculateStack(eggHeight: Int): Double {
if (eggHeight <= 0) return 0.0
return when (mRidingStyle) {
TYPE_RELAX -> eggHeight * Constant.STACK_RATIO + 3
TYPE_NORMAL -> eggHeight * Constant.STACK_RATIO
TYPE_RACE -> eggHeight * Constant.STACK_RATIO - 2
else -> 0.0
}
}
/**
* 计算 REACH 值
*/
private fun calculateReach(stack: Double): Double {
if (stack <= 0) return 0.0
return when (mRidingStyle) {
TYPE_RELAX -> stack / 1.6
TYPE_NORMAL -> stack / 1.48
TYPE_RACE -> stack / 1.36
else -> 0.0
}
}
/**
* 骑行风格类型注解
*/
@Retention(AnnotationRetention.SOURCE)
@IntDef(TYPE_RELAX, TYPE_NORMAL, TYPE_RACE)
internal annotation class RidingStyleTypeDef
}
-
导入相关的 Android 类:
import android.annotation.SuppressLint import android.content.Context import android.os.Bundle import android.view.inputmethod.InputMethodManager import android.widget.Button import android.widget.EditText import android.widget.RadioGroup import android.widget.TextView import androidx.annotation.IntDef import androidx.appcompat.app.AppCompatActivity import java.math.BigDecimal
-
定义
MainActivity
类,继承自AppCompatActivity
:class MainActivity : AppCompatActivity() { // ... }
-
定义了一些常量和变量:
companion object { const val TYPE_RELAX = 0 const val TYPE_NORMAL = 1 const val TYPE_RACE = 2 } @RidingStyleTypeDef private var mRidingStyle = TYPE_NORMAL
这里定义了三个常量
TYPE_RELAX
,TYPE_NORMAL
,TYPE_RACE
分别表示不同的骑行风格,以及一个变量mRidingStyle
用于存储当前所选择的骑行风格,默认为TYPE_NORMAL
。 -
onCreate
方法:override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initView() }
在
onCreate
方法中,首先调用了super.onCreate(savedInstanceState)
,然后通过setContentView(R.layout.activity_main)
设置布局文件activity_main
作为该 Activity 的视图内容。接着调用initView()
方法来初始化视图组件。 -
initView
方法:private fun initView() { // 获取并设置各个视图组件 mEtEggHeight = findViewById(R.id.et_egg_height) mBtnCalculate = findViewById(R.id.btn_calculate) mRadioGroup = findViewById(R.id.radio_group) mTvSeatHeight = findViewById(R.id.tv_seat_height) mTvStackHeight = findViewById(R.id.tv_stack_height) mTvReachHeight = findViewById(R.id.tv_reach_height) // 设置点击软键盘外部时收起软键盘的功能 mEtEggHeight.setOnFocusChangeListener { v, hasFocus -> if (!hasFocus) { val manager: InputMethodManager = applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager manager.hideSoftInputFromWindow(v.windowToken, InputMethodManager.HIDE_NOT_ALWAYS) } } // 设置计算按钮的点击事件监听器 mBtnCalculate.setOnClickListener { mEtEggHeight.clearFocus() calculateData() } // 设置初始选中的骑行风格为 "普通" mRadioGroup.check(R.id.type_normal) mRadioGroup.setOnCheckedChangeListener { _, checkedId -> when (checkedId) { R.id.type_relax -> mRidingStyle = TYPE_RELAX R.id.type_normal -> mRidingStyle = TYPE_NORMAL R.id.type_race -> mRidingStyle = TYPE_RACE } calculateData() } }
在
initView
方法中,首先获取了布局文件中的视图组件,并赋值给对应的成员变量。然后为mEtEggHeight
设置了一个焦点变化监听器,在失去焦点时隐藏软键盘。接着设置了计算按钮mBtnCalculate
的点击事件监听器,在点击时清除mEtEggHeight
的焦点并调用calculateData()
方法进行数据计算。最后,通过mRadioGroup
设置了选中骑行风格的监听器,并根据选中的 RadioButton 来更新mRidingStyle
的值,并调用calculateData()
方法进行数据计算。 -
calculateData
方法:private fun calculateData() { // 获取鸭蛋高度 val eggHeight = getEggHeight() // 计算坐垫高度、STACK 值和 REACH 值 val seatHeight = calculateSeatHeight(eggHeight) val stack = calculateStack(eggHeight) val reach = calculateReach(stack) // 设置计算结果显示在对应的 TextView 上 mTvSeatHeight.text = if (seatHeight == 0.0) { getString(R.string.double_line) } else { BigDecimal(seatHeight).setScale(1, BigDecimal.ROUND_HALF_UP).toString() } mTvStackHeight.text = if (stack == 0.0) { getString(R.string.double_line) } else { BigDecimal(stack).setScale(1, BigDecimal.ROUND_HALF_UP).toString() } mTvReachHeight.text = if (reach == 0.0) { getString(R.string.double_line) } else { BigDecimal(reach).setScale(1, BigDecimal.ROUND_HALF_UP).toString() } }
calculateData
方法用于进行数据计算,并将计算结果显示在对应的 TextView 上。首先,获取鸭蛋高度(骑行者脚踏板到坐垫的距离),然后分别调用calculateSeatHeight
方法、calculateStack
方法和calculateReach
方法进行坐垫高度、STACK 值和 REACH 值的计算。最后,将计算结果显示在对应的TextView
上,并根据结果进行格式化显示。 -
calculateSeatHeight
方法:private fun calculateSeatHeight(eggHeight: Int): Double { if (eggHeight <= 0) return 0.0 return eggHeight * Constant.SEAT_HEIGHT_RATIO }
calculateSeatHeight
方法用于计算坐垫高度,根据给定的鸭蛋高度eggHeight
和常量Constant.SEAT_HEIGHT_RATIO
进行计算,并返回结果。 -
calculateStack
方法:private fun calculateStack(eggHeight: Int): Double { if (eggHeight <= 0) return 0.0 return when (mRidingStyle) { TYPE_RELAX -> eggHeight * Constant.STACK_RATIO + 3 TYPE_NORMAL -> eggHeight * Constant.STACK_RATIO TYPE
_RACE -> eggHeight * Constant.STACK_RATIO - 2
else -> 0.0
}
}
`calculateStack` 方法用于计算 STACK 值(前叉与地面垂直时,前叉顶端至车把水平距离)。根据给定的鸭蛋高度 `eggHeight` 和当前选择的骑行风格 `mRidingStyle`,通过常量 `Constant.STACK_RATIO` 进行计算,并返回结果。
9. `calculateReach` 方法:
```kotlin
private fun calculateReach(stack: Double): Double {
if (stack <= 0) return 0.0
return when (mRidingStyle) {
TYPE_RELAX -> stack / 1.6
TYPE_NORMAL -> stack / 1.48
TYPE_RACE -> stack / 1.36
else -> 0.0
}
}
calculateReach
方法用于计算 REACH 值(前叉与地面垂直时,车把至鞍座水平距离)。根据给定的 STACK 值 stack
和当前选择的骑行风格 mRidingStyle
进行计算,并返回结果。
-
自定义注解
@RidingStyleTypeDef
:@Retention(AnnotationRetention.SOURCE) @IntDef(TYPE_RELAX, TYPE_NORMAL, TYPE_RACE) internal annotation class RidingStyleTypeDef
这是一个自定义的注解,用于限制某个整数值只能在指定的范围内取值。在这里,它用于限制骑行风格常量的取值只能是
TYPE_RELAX
,TYPE_NORMAL
,TYPE_RACE
中的一个。
三.项目源码
百度网盘:
链接:https://pan.baidu.com/s/19nSterWen-JMVOko7120UQ?pwd=jynl
提取码:jynl
有软件开发请私信作者
或+vx:15135757306