购票系统

实现功能
开发手机购票软件,界面显示内容包括起点站,终点站,购票数量,收费规则:地铁每三站收费一元,总站数除三余站不足三站也按照一元收费,起点站不算。填写信息后显示金额,如果金额正确点击购票按钮并显示购票成功

完成代码:
架构:

具体代码:
Line

点击查看代码
package com.qi.demo.model

data class Line(
    val id: Int,
    val name: String,
    val stations: List<Station>
)
Station
点击查看代码
package com.qi.demo.model

data class Station(
    val name: String,
    val index: Int,
    val lineId: Int,
    val transferTo: List<Int> = emptyList()
)
MainActivity
点击查看代码
package com.qi.demo

import android.os.Bundle
import android.widget.*
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.qi.demo.model.Line
import com.qi.demo.model.Station

class MainActivity : AppCompatActivity() {
    private lateinit var spinnerStart: Spinner
    private lateinit var spinnerEnd: Spinner
    private lateinit var editTextTickets: EditText
    private lateinit var textViewAmount: TextView
    private lateinit var buttonCalculate: Button
    private lateinit var buttonBuy: Button


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        
        initViews()
        setupSpinners()
        setupListeners()
    }

    private fun initViews() {
        spinnerStart = findViewById(R.id.spinnerStart)
        spinnerEnd = findViewById(R.id.spinnerEnd)
        editTextTickets = findViewById(R.id.editTextTickets)
        textViewAmount = findViewById(R.id.textViewAmount)
        buttonCalculate = findViewById(R.id.buttonCalculate)
        buttonBuy = findViewById(R.id.buttonBuy)
    }

    private val line1 = Line(1, "1号线", listOf(
        Station("西王", 0, 1),
        Station("时光街", 1, 1),
        Station("长城桥", 2, 1),
        Station("和平医院", 3, 1),
        Station("烈士陵园", 4, 1),
        Station("新百广场", 5, 1, listOf(3)),
        Station("解放广场", 6, 1),
        Station("平安大街", 7, 1),
        Station("北国商城", 8, 1, listOf(2)),
        Station("博物院", 9, 1),
        Station("体育场", 10, 1),
        Station("北宋", 11, 1),
        Station("谈固", 12, 1),
        Station("朝晖桥", 13, 1),
        Station("白佛", 14, 1),
        Station("留村", 15, 1),
        Station("火炬广场", 16, 1),
        Station("石家庄东站", 17, 1),
        Station("南村", 18, 1),
        Station("洨河大道", 19, 1),
        Station("西庄", 20, 1),
        Station("东庄", 21, 1),
        Station("会展中心", 22, 1),
        Station("商务中心", 23, 1),
        Station("园博园", 24, 1),
        Station("福泽", 25, 1)
    ))

    private val line2 = Line(2, "2号线", listOf(
        Station("柳辛庄", 0, 2),
        Station("庄窠·铁道大学", 1, 2),
        Station("义堂", 2, 2),
        Station("建和桥", 3, 2),
        Station("长安公园", 4, 2),
        Station("北国商城", 5, 2, listOf(1)),
        Station("裕华路", 6, 2),
        Station("槐中路", 7, 2),
        Station("欧韵公园", 8, 2),
        Station("元村", 9, 2),
        Station("石家庄", 10, 2, listOf(3)),
        Station("塔坛", 11, 2),
        Station("仓丰路留村", 12, 2),
        Station("南位", 13, 2),
        Station("嘉华路", 14, 2)
    ))

    private val line3 = Line(3, "3号线", listOf(
        Station("西三庄", 0, 3),
        Station("高柱", 1, 3),
        Station("柏林庄", 2, 3),
        Station("市庄", 3, 3),
        Station("市二中", 4, 3),
        Station("新百广场", 5, 3, listOf(1)),
        Station("东里", 6, 3),
        Station("槐安桥", 7, 3),
        Station("西三教", 8, 3),
        Station("石家庄", 9, 3, listOf(2)),
        Station("汇通路", 10, 3),
        Station("孙村", 11, 3),
        Station("塔冢", 12, 3),
        Station("东王", 13, 3),
        Station("南王", 14, 3),
        Station("位同", 15, 3),
        Station("东二环南路", 16, 3),
        Station("西仰陵", 17, 3),
        Station("中仰陵", 18, 3),
        Station("南豆", 19, 3),
        Station("太行南大街", 20, 3),
        Station("乐乡", 21, 3)
    ))

    private val allLines = listOf(line1, line2, line3)
    private val allStations = allLines.flatMap { it.stations }

    private fun calculateFare() {
        val startStation = allStations[spinnerStart.selectedItemPosition]
        val endStation = allStations[spinnerEnd.selectedItemPosition]
        val ticketCount = editTextTickets.text.toString().toIntOrNull() ?: 0

        if (startStation.name == endStation.name) {
            Toast.makeText(this, "起点站和终点站不能相同", Toast.LENGTH_SHORT).show()
            return
        }

        val stationCount = calculateStationCount(startStation, endStation)
        val farePerTicket = (stationCount + 2) / 3
        val totalFare = farePerTicket * ticketCount

        textViewAmount.text = "总金额:${totalFare}元"
        buttonBuy.isEnabled = true
    }

    private fun calculateStationCount(start: Station, end: Station): Int {
        // 如果在同一条线路上
        if (start.lineId == end.lineId) {
            return Math.abs(start.index - end.index)
        }

        // 需要换乘的情况
        var minStations = Int.MAX_VALUE
        
        // 遍历所有可能的换乘路径
        for (transfer1 in allStations.filter { it.transferTo.isNotEmpty() && it.lineId == start.lineId }) {
            // 直接换乘到终点线路
            if (transfer1.transferTo.contains(end.lineId)) {
                val count = Math.abs(start.index - transfer1.index) +
                        Math.abs(end.index - allStations.find {
                            it.name == transfer1.name && it.lineId == end.lineId
                        }?.index!! ?: 0)
                minStations = minOf(minStations, count)
            }
            
            // 需要二次换乘
            for (transfer2 in allStations.filter { 
                it.transferTo.isNotEmpty() && 
                it.lineId == end.lineId && 
                it.name != transfer1.name 
            }) {
                // 找到中间线路的换乘站
                val midTransfer1 = allStations.find { 
                    it.name == transfer1.name && 
                    transfer1.transferTo.contains(it.lineId) 
                }
                val midTransfer2 = allStations.find { 
                    it.name == transfer2.name && 
                    transfer2.transferTo.contains(midTransfer1?.lineId ?: -1) 
                }
                
                if (midTransfer1 != null && midTransfer2 != null) {
                    val count = Math.abs(start.index - transfer1.index) +
                            Math.abs(midTransfer1.index - midTransfer2.index) +
                            Math.abs(end.index - transfer2.index)
                    minStations = minOf(minStations, count)
                }
            }
        }
        
        return if (minStations == Int.MAX_VALUE) 0 else minStations
    }

    private fun setupSpinners() {
        val adapter = ArrayAdapter(
            this,
            android.R.layout.simple_spinner_item,
            allStations.map { "${it.name}(${allLines[it.lineId-1].name})" }
        )
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        
        spinnerStart.adapter = adapter
        spinnerEnd.adapter = adapter
    }

    private fun setupListeners() {
        buttonCalculate.setOnClickListener {
            calculateFare()
        }

        buttonBuy.setOnClickListener {
            Toast.makeText(this, "购票成功!", Toast.LENGTH_SHORT).show()
            resetForm()
        }
    }

    private fun resetForm() {
        spinnerStart.setSelection(0)
        spinnerEnd.setSelection(0)
        editTextTickets.setText("")
        textViewAmount.text = ""
        buttonBuy.isEnabled = false
    }
}
activity_main.xml
点击查看代码
  <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/spinnerStart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toTopOf="parent" />

    <Spinner
        android:id="@+id/spinnerEnd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/spinnerStart" />

    <EditText
        android:id="@+id/editTextTickets"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:hint="请输入购票数量"
        android:inputType="number"
        app:layout_constraintTop_toBottomOf="@id/spinnerEnd" />

    <TextView
        android:id="@+id/textViewAmount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:textSize="18sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/editTextTickets" />

    <Button
        android:id="@+id/buttonCalculate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="计算金额"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textViewAmount" />

    <Button
        android:id="@+id/buttonBuy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:text="购买车票"
        android:enabled="false"
        app:layout_constraintStart_toEndOf="@id/buttonCalculate"
        app:layout_constraintTop_toTopOf="@id/buttonCalculate" />

</androidx.constraintlayout.widget.ConstraintLayout>
实现效果: ![](https://img2024.cnblogs.com/blog/3474860/202503/3474860-20250314215843137-430580726.png)
posted @ 2025-03-14 21:59  QixunQiu  阅读(31)  评论(0)    收藏  举报