Android开发实战---一个汽车销售APP,有汽车列表页、汽车详情页、贷款计算页3个界面。

Android开发实战设计并实现一个汽车销售APP,要求至少有汽车列表页、汽车详情页、贷款计算页3个界面。
已开源:https://github.com/yan123666/wlf
实现结果:

4e08581dc7992b6c5f8b9555f7ed8c3

5d4d51a8b2991b4215ad37f29af73fd

aa8b838c52ca8dc8bbcc92f2ca788bd

1.计算金额界面
package com.car.car

import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity

/**
 * 计算金额界面
 */
class CalculateActivity : AppCompatActivity() {
    private  var  dividel:Boolean=true
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_calculate_wlf)
         //获取传递过来车辆信息
        var carBean:CarBean = intent.getSerializableExtra("car") as CarBean

        //显示车辆价格
        var et_price = findViewById<TextView>(R.id.et_price)
        et_price.setText("¥"+(carBean.price!!.toDouble()*10000))

        //初始化布局
        var seek_DisCount_Percent = findViewById<SeekBar>(R.id.seek_DisCount_Percent)
        var tv_DisCount_Account = findViewById<TextView>(R.id.tv_DisCount_Account)
        var tv_Total = findViewById<TextView>(R.id.tv_Total)
        var tv_percent = findViewById<TextView>(R.id.tv_percent)
        var rg = findViewById<RadioGroup>(R.id.rg)
        var rb_no = findViewById<RadioButton>(R.id.rb_no)
        var rb_yes = findViewById<RadioButton>(R.id.rb_yes)
        var tv_DownPayment = findViewById<TextView>(R.id.tv_DownPayment)
        var tv_Loan = findViewById<TextView>(R.id.tv_Loan)
        var sp_Periods = findViewById<Spinner>(R.id.sp_Periods)
        var tv_period = findViewById<TextView>(R.id.tv_period)


        //给下拉框添加监听事件  选择分期时间
        sp_Periods.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
                //判断是否分期 ,如果分期 计算
              if (dividel){
                  //首付费用 分期费用各一半
                  tv_DownPayment.setText("¥"+(carBean.price!!.toDouble()*10000/2))
                  //分期费用
                  tv_Loan.setText("¥"+(carBean.price!!.toDouble()*10000/2))
                    //6 个月  12个月  24个月  每期的费用
                  if (i==0){
                      tv_period.setText("¥"+(carBean.price!!.toDouble()*10000/2/6))
                  }else if (i==1){
                      tv_period.setText("¥"+(carBean.price!!.toDouble()*10000/2/12))
                  }else if (i==2){
                      tv_period.setText("¥"+(carBean.price!!.toDouble()*10000/2/24))
                  }
              }

            }

            override fun onNothingSelected(adapterView: AdapterView<*>?) {}
        }

        //是否分期切换监听
        rg.setOnCheckedChangeListener { group, checkedId ->
            //分期
            if (checkedId == R.id.rb_yes) {
                dividel = true
                tv_DownPayment.setText("¥"+(carBean.price!!.toDouble()*10000/2))
                tv_Loan.setText("¥"+(carBean.price!!.toDouble()*10000/2))

                val i=sp_Periods.selectedItemPosition  //当前选中期数

                //每期费用
                if (i==0){
                    tv_period.setText("¥"+(carBean.price!!.toDouble()*10000/2/6))
                }else if (i==1){
                    tv_period.setText("¥"+(carBean.price!!.toDouble()*10000/2/12))
                }else if (i==2){
                    tv_Loan.setText("¥"+(carBean.price!!.toDouble()*10000/2/24))
                }
            } else {
                //不分期
                dividel = false
                tv_DownPayment.setText("")
                tv_Loan.setText("")
                //每期费用
                tv_period.setText("")

            }
        }
        /**
         * 监听优惠力度 当优惠力度发生改变的时候 实际总的金额也变化
         */
        seek_DisCount_Percent.setOnSeekBarChangeListener(object :SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {

                tv_percent.setText(""+(progress)+"%")
                tv_Total.setText("¥"+(carBean.price!!.toDouble()*10000-carBean.price!!.toDouble()*10000*progress/100))
                tv_DisCount_Account.setText("¥"+(carBean.price!!.toDouble()*10000*progress/100))

            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {

            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {

            }

        })
    }
}
2.车辆列表适配器
package com.car.car

import android.content.Context
import android.view.View
import android.widget.BaseAdapter
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import java.util.ArrayList

/**
 * 车辆列表适配器
 */
class CarAdapter(context: Context, mData: MutableList<CarBean>) : BaseAdapter() {
    private var data = mData
    private var  mContext=context;
    override fun getCount(): Int {
        return data.size
    }

    override fun getItem(position: Int): Any {
        return data[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }


    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val   convertView = View.inflate(mContext, R.layout.item_layout_wlf, null)
        var car = this.data[position]

        /**
         * 初始化控件
         */
        val  img=convertView.findViewById<ImageView>(R.id.iv_img)  //车辆图片
        val  tv_title=convertView.findViewById<TextView>(R.id.tv_title) //车辆名
        val  tv_mileage=convertView.findViewById<TextView>(R.id.tv_mileage) //公里数
        val  tv_price=convertView.findViewById<TextView>(R.id.tv_price) //车辆价格
        //车辆图片
        img.setImageResource(car.img)
        //车辆名字
        tv_title.text = car.name
        //车辆公里数
        tv_mileage.text = car.describe;
        //车辆价格
        tv_price.text = car.price+"万";

        return convertView
    }
}
3.车辆类
package com.car.car

import java.io.Serializable

/**
 * 车辆类
 */
class CarBean(id: Int, type: String, name: String, price: String, describe: String, pic: Int) : Serializable {
    var id = id //车辆ID
    var type: String? = type  //车辆类型
    var name: String? = name  //车辆名
    var price: String? = price //车辆价格
    var describe: String? = describe //公里数描述
    var img = pic //车辆图片
}
4.数据库操作类
package com.car.car

import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.SQLException
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper


/**
 * sqlite 数据库操作类
 */
class DatabaseUtil
(

    private val mCtx: Context
) {
    private var mDbHelper: DatabaseHelper? = null
    private var mDb: SQLiteDatabase? = null


    private class DatabaseHelper  constructor(context: Context?) :
        SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

        override fun onCreate(db: SQLiteDatabase) {
            //创建表
            db.execSQL(CREATE_TABLE)
        }


        override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {

        }
    }

    /**
     * 打开数据库
     *
     * @return instance of DatabaseUtil
     * @throws SQLException
     */
    @Throws(SQLException::class)
    fun open(): DatabaseUtil {
        mDbHelper = DatabaseHelper(mCtx)
        mDb = mDbHelper!!.writableDatabase
        return this
    }

    /**
     * This method is used for closing the connection.
     */
    fun close() {
        mDbHelper!!.close()
    }

    /**
     * 插入数据
     *
     * @param name
     * @param grade
     * @return long
     */
    fun insert(type: String?, name: String?, price: String?, describe: String?, img:Int): Long {
        val initialValues = ContentValues()
                initialValues.put("type", type);
        initialValues.put("name", name);
        initialValues.put("price", price);
        initialValues.put("describe", describe);
        initialValues.put("img", img);
        return mDb!!.insert(DATABASE_TABLE, null, initialValues)
    }

    /**
     * 查询全部数据
     */
    @SuppressLint("Range")
    fun queryAllPersonData(): List<CarBean>? {

        //查询全部数据
        val cursor: Cursor =
            mDb!!.query(DATABASE_TABLE, null, null, null, null, null, null, null)
        val list: MutableList<CarBean> = ArrayList()
        if (cursor.count > 0) {
            //移动到首位
            cursor.moveToFirst()
            for (i in 0 until cursor.count) {
                val id = cursor.getInt(cursor.getColumnIndex("id"))
                val type = cursor.getString(cursor.getColumnIndex("type"))
                val name = cursor.getString(cursor.getColumnIndex("name"))
                val price = cursor.getString(cursor.getColumnIndex("price"))
                val describe = cursor.getString(cursor.getColumnIndex("describe"))
                val pic = cursor.getInt(cursor.getColumnIndex("img"))
                val model = CarBean(id,type,name,price,describe,pic)


                list.add(model)
                //移动到下一位
                cursor.moveToNext()
            }
        }
        cursor.close()
        mDb!!.close()
        return list
    }

    /**
     * This method will deleteAll record.
     *
     * @return
     */
    fun deleteAll(): Boolean {
        return mDb!!.delete(DATABASE_TABLE, " 1 ", null) > 0
    }


    companion object {
        private const val TAG = "DatabaseUtil"

        /**
         * Database Name  数据库名
         */
        private const val DATABASE_NAME = "car_data"

        /**
         * Database Version  数据库版本
         */
        private const val DATABASE_VERSION = 1

        /**
         * Table Name   数据库表名
         */
        private const val DATABASE_TABLE = "tb_car"

        /**
         * Table columns  数据库字段名
         */
        const val KEY_ID = "id"
        const val KEY_TYPE = "type"
        const val KEY_NAME = "name"
        const val KEY_PRICE = "price"
        const val KEY_DESCRIBE = "describe"
        const val KEY_IMG = "img"

        /**
         * Database creation sql statement
         */
        private const val CREATE_TABLE =
            ("create table " + DATABASE_TABLE + " (" + KEY_ID + " integer primary key autoincrement, "
                    + KEY_TYPE + " text not null, "
                    + KEY_NAME + " text not null, "
                    + KEY_PRICE + " text not null, "
                    + KEY_DESCRIBE + " text not null, "
                    + KEY_IMG + " integer not null);")
    }
}
5.车辆详情界面
package com.car.car

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView

/**
 * 车辆详情界面
 */
class DetailsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_details_wlf)
        //获取传递数据
        var carBean:CarBean = intent.getSerializableExtra("car") as CarBean
        //初始化布局
        var iv_img = findViewById<ImageView>(R.id.iv_img)
        var tv_detail_msg = findViewById<TextView>(R.id.tv_detail_msg)
        var bt_buy = findViewById<Button>(R.id.bt_buy)

        //显示数据 图片显示和详情
        iv_img.setImageResource(carBean.img)
        tv_detail_msg.setText(carBean.name+carBean.describe+carBean.price+"万")
        //跳转到计算界面
        bt_buy.setOnClickListener {
            val intent = Intent(this, CalculateActivity::class.java);
            intent.putExtra("car", carBean)
            startActivity(intent)
        }

    }
}
6.车辆列表界面
package com.car.car

import android.content.Intent
import android.os.Bundle
import android.widget.AdapterView
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity

/**
 * 车辆列表界面
 */
class MainActivity : AppCompatActivity() {
    private  lateinit var listView: ListView
    private var carAdapter: CarAdapter?=null
    private  var data= mutableListOf<CarBean>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main_wlf)
        listView = findViewById<ListView>(R.id.lv)

        initData()
        //跳转到详情界面
        listView.onItemClickListener =
            AdapterView.OnItemClickListener { adapterView, view, i, l ->
                //传递车辆信息
                val intent = Intent(this, DetailsActivity::class.java);
                intent.putExtra("car", data[i])
                startActivity(intent)
            }

    }

    /**
     * 初始化数据
     */
    private fun initData() {
        //数据库开启
        val dbUtil=DatabaseUtil(this);
        dbUtil.open()
        //查询数据库里是否存在数据
        var queryAllPersonData = dbUtil.queryAllPersonData()

        //存在数据
        if (null!=queryAllPersonData&&queryAllPersonData.size>0){
            data= queryAllPersonData as MutableList<CarBean>
            //初始化是脾气
            carAdapter = CarAdapter(this,data)
            //设置适配器
            listView.adapter=carAdapter
        }else{
            //不存在 插入3个默认数据
            dbUtil.open()
            //插入数据
            dbUtil.insert("轿车","小鹏汽车P7 2022款","18.5","2023年(700公里)",R.mipmap.img1);
            dbUtil.insert("轿车","保时捷 2021款","158.5","2023年(2700公里)",R.mipmap.img2);
            dbUtil.insert("轿车","别克E5 2023款","20.5","2023年(500公里)",R.mipmap.img3);
            //再次查询数据库  确认查询成功  设置适配器现实数据
            var queryAllPersonData1 = dbUtil.queryAllPersonData()
            data= queryAllPersonData1 as MutableList<CarBean>
            carAdapter = CarAdapter(this,data)
            listView.adapter=carAdapter
        }

    }
}

界面设计:

1.金额计算页面:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    android:padding="20sp"
    tools:context=".CalculateActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="Price"
            android:layout_height="wrap_content"></TextView>
        <EditText
            android:id="@+id/et_price"
            android:layout_width="0dp"
            android:gravity="right|center_vertical"
            android:layout_weight="1"
            android:layout_height="match_parent"></EditText>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="DisCount Percent"
            android:layout_height="wrap_content"></TextView>
        <SeekBar
            android:id="@+id/seek_DisCount_Percent"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"></SeekBar>
        <TextView
            android:id="@+id/tv_percent"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"></TextView>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="DisCount Account"
            android:layout_height="wrap_content"></TextView>
        <TextView
            android:id="@+id/tv_DisCount_Account"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="right|center_vertical"
            android:layout_height="match_parent"></TextView>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="Total"
            android:layout_height="wrap_content"></TextView>
        <TextView
            android:id="@+id/tv_Total"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="right|center_vertical"
            android:layout_height="match_parent"></TextView>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:layout_marginTop="40dp"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="Dividel?"
            android:layout_gravity="center_vertical"
            android:layout_height="wrap_content"></TextView>
        <RadioGroup
            android:id="@+id/rg"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical"
            android:layout_height="wrap_content">

            <RadioButton
                android:id="@+id/rb_no"
                android:layout_width="wrap_content"
                android:text="No"
                android:layout_height="wrap_content"></RadioButton>
            <RadioButton
                android:id="@+id/rb_yes"
                android:layout_width="wrap_content"
                android:text="Yes"
                android:checked="true"
                android:layout_height="wrap_content"></RadioButton>
        </RadioGroup>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="DownPayment"
            android:layout_height="wrap_content"></TextView>
        <TextView
            android:id="@+id/tv_DownPayment"
            android:layout_width="0dp"
            android:gravity="right|center_vertical"
            android:layout_weight="1"
            android:layout_height="match_parent"></TextView>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="Loan"
            android:layout_height="wrap_content"></TextView>
        <TextView
            android:id="@+id/tv_Loan"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="right|center_vertical"
            android:layout_height="match_parent"></TextView>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="Periods"
            android:layout_height="wrap_content"></TextView>
        <Spinner
            android:id="@+id/sp_Periods"
            android:layout_width="0dp"
            android:gravity="right"
            android:layout_marginLeft="20sp"
            android:entries="@array/phones_array"
            android:layout_weight="1"
            android:layout_height="match_parent"></Spinner>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
        <TextView

            android:layout_width="wrap_content"
            android:text="Per period"
            android:layout_height="wrap_content"></TextView>
        <TextView
            android:id="@+id/tv_period"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="right|center_vertical"
            android:layout_height="match_parent"></TextView>
    </LinearLayout>
</LinearLayout>
2.立即购买控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp"
    tools:context=".DetailsActivity">
    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></ImageView>
    <TextView
        android:id="@+id/tv_detail_msg"
        android:layout_width="match_parent"
        android:textColor="#DD306B"
        android:layout_marginTop="20sp"
        android:textSize="14sp"
        android:layout_height="wrap_content"></TextView>
    <Button
        android:id="@+id/bt_buy"
        android:layout_width="wrap_content"
        android:text="立即购买"
        android:layout_marginTop="20dp"
        android:layout_gravity="center_horizontal|bottom"


        android:layout_height="wrap_content"></Button>

</LinearLayout>
3.车辆展示页面
<?xml version="1.0" encoding="utf-8"?>
<ListView 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:layout_width="match_parent"
     android:id="@+id/lv"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


</ListView>
4.布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="120dp"
        android:layout_height="120dp"></ImageView>
    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:paddingLeft="10dp"
        android:layout_height="120dp">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:gravity="center_vertical"
            android:textColor="#1677C5"
            android:textSize="16sp"
            android:layout_height="45dp"></TextView>
        <TextView
            android:id="@+id/tv_mileage"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:textColor="#505151"
            android:gravity="center_vertical"
            android:textSize="12sp"
            ></TextView>
        <TextView
            android:id="@+id/tv_price"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:textColor="#131313"
            android:gravity="center_vertical"
            android:textSize="18sp"
            android:layout_weight="1"
            ></TextView>
    </LinearLayout>
</LinearLayout>

配置文件:

strings.xml

<resources>
    <string name="app_name">汽车销售APP</string>

    <string-array name = "phones_array">
        <item>6 months</item>
        <item>12 months</item>
        <item>24 months</item>
    </string-array>
</resources>

themes.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.Car" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

themes.xml

详细项目正在发布到开源社区ing

猜你喜欢

转载自blog.csdn.net/m0_63324772/article/details/131213510