基于 Android Studio 仿故宫博物院(馆)App--原创

目录

一、项目演示

二、开发环境

三、项目简介

四、项目详情

五、项目完整源码


一、项目演示

基于 Android Studio仿故宫博物院(馆)App--原创

二、开发环境

三、项目简介

       该项目隶属于编程乐学团队原创 Android Studio 项目,其中页面素材和布局来自于故宫博物院小程序和故宫展览APP。

        该项目中文注释高达95%,如下图所示部分注释展示:

四、项目详情

1.启动页

这段代码是一个简单的Android应用程序启动活动(Activity),具体功能如下:

1. **延迟进入登录页面:**
   - 在 `onCreate()` 方法中,使用 `Handler` 和 `Runnable` 实现了一个延迟执行的功能,延迟时间为3秒。
   - `runnable` 对象的 `run()` 方法调用了 `tomainActive()` 方法,在延迟结束后启动 `LoginRegisterActivity` 并关闭当前的 `StartActivity`。

2. **计时器功能:**
   - 定义了一个内部类 `TimeCount`,继承自 `CountDownTimer`,用于执行一个四秒的倒计时操作,每隔一秒触发一次。
   - `onFinish()` 方法中,倒计时结束后移除了 `handler` 中的 `runnable` 对象,确保不会在倒计时结束后再次跳转到登录页面。

3. **Activity 生命周期方法:**
   - `onCreate()` 方法中,设置了布局文件 `activity_start.xml` 作为界面显示内容,并启动了延迟执行和计时器。
   - `onDestroy()` 方法中未显示重写,但在 `toMainActive()` 方法中的 `finish()` 方法确保了在跳转完成后关闭当前 Activity。

总体来说,该代码实现了在应用启动后延迟3秒进入登录页面,并在倒计时4秒后取消延迟,确保用户在启动页面停留不超过指定时间后自动跳转到登录页面。

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/start"
    tools:context=".Activity.StartActivity">

    <Button
        android:id="@+id/btn_skip"
        android:layout_width="70dp"
        android:layout_height="30dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="16dp"
        android:background="@drawable/start_bg"
        android:text="跳过"
        android:textColor="#fff"
        android:textSize="12sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

2.登陆、注册、忘记密码

主要实现了登陆注册找回密码功能,全部使用到SQLite数据库进行操作

   // 定义一个私有方法login,用于处理用户登录逻辑
    private void login() {
        // 为btnLogin按钮设置点击事件监听器
        btnLogin.setOnClickListener(v -> {
            // 从etMail(可能是一个EditText控件)中获取文本内容,并转换为字符串,赋值给mail变量
            String mail = etMail.getText().toString();
            // 从etPassword(可能是一个EditText控件)中获取文本内容,并转换为字符串,赋值给password变量
            String password = etPassword.getText().toString();
            // 判断mail或password是否为空
            if (mail.isEmpty() || password.isEmpty()) {
                // 如果其中之一为空,则显示一个Toast提示信息“请确保所有内容不为空!”
                Toast.makeText(this, "请确保所有内容不为空!", Toast.LENGTH_SHORT).show();
                // 提前返回,不再执行后续代码
                return;
            }
            // 检查RadioButton(rb)是否被选中
            boolean isRbChecked = rb.isChecked();

            // 判断RadioButton是否未被选中
            if (!isRbChecked) {
                // 如果未被选中,则显示一个Toast提示信息“请勾选同意注册协议!”
                Toast.makeText(this, "请勾选同意注册协议!", Toast.LENGTH_SHORT).show();
                // 提前返回,不再执行后续代码
                return;
            }
            // 调用userHelper的validateUser方法验证用户的邮箱和密码是否正确,结果赋值给b变量
            boolean b = userHelper.validateUser(mail, password);
            // 判断用户验证是否成功
            if (b) {
                // 如果验证成功,则显示一个Toast提示信息“登录成功!”
                Toast.makeText(this, "登录成功!", Toast.LENGTH_SHORT).show();
                // 获取SharedPreferences对象,名称为"User",模式为私有模式
                SharedPreferences sharedPreferences = getSharedPreferences("User", Context.MODE_PRIVATE);
                // 获取SharedPreferences.Editor对象,用于编辑SharedPreferences数据
                SharedPreferences.Editor editor = sharedPreferences.edit();
                // 将邮箱和密码存储到SharedPreferences中
                editor.putString("mail", mail);
                editor.putString("password", password);
                // 提交修改
                editor.apply();
                // 结束当前Activity
                finish();
            } else {
                // 如果验证失败,则显示一个Toast提示信息“登录失败,请重试!”
                Toast.makeText(this, "登录失败,请重试!", Toast.LENGTH_SHORT).show();
                // 清空etPassword和etMail的文本内容
                etPassword.setText("");
                etMail.setText("");
            }
        });
    }

    // 定义一个私有方法register,用于处理注册页面的跳转
    private void register() {
        // 为tvRegister(可能是一个TextView控件)设置点击事件监听器
        tvRegister.setOnClickListener(v -> {
            // 创建一个Intent,用于从当前Activity跳转到RegisterActivity
            Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
            // 启动RegisterActivity
            startActivity(intent);
        });
    }

    // 定义一个私有方法back,用于处理返回操作
    private void back() {
        // 为imgBack(可能是一个ImageView控件)设置点击事件监听器
        imgBack.setOnClickListener(v -> {
            // 结束当前Activity
            finish();
        });
    }

    // 定义一个私有方法forgot,用于处理忘记密码页面的跳转
    private void forgot() {
        // 为tvForget(可能是一个TextView控件)设置点击事件监听器
        tvForget.setOnClickListener(v -> {
            // 创建一个Intent,用于从当前Activity跳转到ForgotPasswordActivity
            Intent intent = new Intent(LoginActivity.this, ForgotPasswordActivity.class);
            // 启动ForgotPasswordActivity
            startActivity(intent);
        });
    }

`LoginActivity` 是一个 Android 应用中的登录界面,提供用户登录、注册和忘记密码功能。主要功能包括:

- **登录处理**:检查用户输入的邮箱和密码是否为空,验证是否勾选了协议,使用 `UserHelper` 验证用户信息,验证成功后保存信息到 `SharedPreferences`。
- **注册和忘记密码跳转**:点击相应的按钮跳转到注册页面或忘记密码页面。
- **返回操作**:点击返回按钮结束当前页面。

该活动在 `onCreate` 方法中初始化视图组件,并设置了相应的点击事件处理。

    private void register() {
        // 设置注册按钮的点击事件监听器
        btnRegister.setOnClickListener(v -> {
            // 获取用户输入的邮箱、用户名和密码
            String mail = etMail.getText().toString();
            String name = etName.getText().toString();
            String password = etPassword.getText().toString();

            // 检查邮箱、用户名和密码是否为空
            if (mail.isEmpty() || name.isEmpty() || password.isEmpty()) {
                // 如果有任何字段为空,显示提示消息
                Toast.makeText(this, "请确保所有内容不为空!", Toast.LENGTH_SHORT).show();
                return; // 退出方法
            }

            // 检查密码长度是否在6到16个字符之间
            if (password.length() < 6 || password.length() > 16) {
                // 如果密码长度不符合要求,显示提示消息
                Toast.makeText(this, "密码长度应为6到16个字符!", Toast.LENGTH_SHORT).show();
                return; // 退出方法
            }

            // 检查同意注册协议的 RadioButton 是否被选中
            boolean isRbChecked = rb.isChecked();

            if (!isRbChecked) {
                // 如果没有勾选同意注册协议,显示提示消息
                Toast.makeText(this, "请勾选同意注册协议!", Toast.LENGTH_SHORT).show();
                return; // 退出方法
            }

            // 调用 userHelper 的 addUser 方法注册用户,并获取返回结果
            boolean b = userHelper.addUser(mail, name, password);
            if (b) {
                // 如果注册成功,显示成功消息并关闭当前活动
                Toast.makeText(this, "注册成功!", Toast.LENGTH_SHORT).show();
                finish(); // 关闭当前活动
            } else {
                // 如果注册失败,显示失败消息,清空输入框内容
                Toast.makeText(this, "注册失败,请重试!", Toast.LENGTH_SHORT).show();
                etPassword.setText(""); // 清空密码输入框
                etMail.setText(""); // 清空邮箱输入框
                etName.setText(""); // 清空用户名输入框
            }
        });
    }

`register()` 方法用于处理用户注册逻辑。其功能包括:

1. **设置注册按钮点击事件监听器**:当点击注册按钮时,执行以下操作。

2. **获取用户输入**:从输入框中获取用户的邮箱、用户名和密码。

3. **输入验证**:
   - 检查邮箱、用户名和密码是否为空;若为空,显示提示消息。
   - 验证密码长度是否在 6 到 16 个字符之间;若不符合要求,显示提示消息。

4. **协议勾选验证**:检查用户是否勾选了同意注册协议的 `RadioButton`;若未勾选,显示提示消息。

5. **调用注册方法**:
   - 使用 `UserHelper` 的 `addUser()` 方法注册用户,并根据返回结果显示相应的消息。
   - 注册成功则显示成功消息并关闭当前活动。
   - 注册失败则显示失败消息,并清空输入框内容。

这个方法确保用户在注册前填写所有必要的信息,并符合基本的验证要求。

3.用户首页、购票约展览、地图导览

这个项目是一个预约系统的功能实现,主要包括以下几个功能点:

1. **预约按钮点击事件**:
   - 设置预约按钮的点击事件监听器。

2. **日期选择检查**:
   - 获取用户选择的参观日期,并检查是否选择了有效的日期。如果没有选择,弹出提示信息。

3. **时间选择检查**:
   - 获取用户选择的参观时间,并检查是否选择了有效的时间。如果没有选择,弹出提示信息。

4. **订单ID生成**:
   - 生成一个唯一的订单ID,格式为“D”加上当前时间的年月日时分秒。

5. **订单时间记录**:
   - 获取当前时间,并格式化为“yyyy-MM-dd HH:mm:ss”的字符串,记录为订单时间。

6. **票务信息初始化**:
   - 初始化各种票务信息,包括票种、票数和总价,用于后续的数据库插入操作。

7. **票务信息处理**:
   - 遍历适配器中的数据,检查票数,计算每种票的总价,并将相关信息存入对应的 `StringBuilder` 中。

8. **数据库插入操作**:
   - 如果有选择票种,将订单数据(包括用户邮箱、订单ID、订单时间、参观日期、参观时间以及各票种的票数和总价)插入到数据库中,并设置订单状态为“待支付”。

9. **预约成功提示及页面跳转**:
   - 弹出预约成功的提示信息,并跳转到订单页面。

10. **票种选择检查**:
    - 如果没有选择任何票种,弹出提示信息提醒用户选择票种。

 private void reserve() {
        // 设置预约按钮的点击事件
        btnReserve.setOnClickListener(v -> {
            // 获取选择的参观日期
            String visitDate = selectedDateText.getText().toString();

            // 检查参观日期是否被选择
            if (visitDate.equals("点击选择参观日期")) {
                Toast.makeText(this, "请选择参观日期!", Toast.LENGTH_SHORT).show();
                return; // 退出方法
            }

            // 获取选中的参观时间单选按钮的 ID
            int selectedId = rb.getCheckedRadioButtonId();

            // 根据 ID 查找选中的单选按钮
            RadioButton selectedRadioButton = findViewById(selectedId);

            // 检查是否选择了参观时间
            if (selectedRadioButton == null) {
                Toast.makeText(this, "请选择参观时间", Toast.LENGTH_SHORT).show();
                return; // 退出方法
            }

            // 获取选中的参观时间
            String visitTime = selectedRadioButton.getText().toString();

            // 生成订单 ID
            String orderId = "D" + new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()) {{
                setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置时区为上海
            }}.format(new Date());

            // 获取当前时间作为订单时间
            String orderTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) {{
                setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置时区为上海
            }}.format(new Date());

            // 初始化票务信息
            boolean hasTickets = false;
            StringBuilder ticketType1 = new StringBuilder();
            StringBuilder ticketCount1 = new StringBuilder();
            StringBuilder totalPrice1 = new StringBuilder();
            StringBuilder ticketType2 = new StringBuilder();
            StringBuilder ticketCount2 = new StringBuilder();
            StringBuilder totalPrice2 = new StringBuilder();
            StringBuilder ticketType3 = new StringBuilder();
            StringBuilder ticketCount3 = new StringBuilder();
            StringBuilder totalPrice3 = new StringBuilder();
            StringBuilder ticketType4 = new StringBuilder();
            StringBuilder ticketCount4 = new StringBuilder();
            StringBuilder totalPrice4 = new StringBuilder();

            int count = 0; // 票种计数器

            // 遍历适配器中的数据
            for (Map<String, String> item : adapter.getData()) {
                String ticketCountStr = item.get("ticketCount"); // 获取票数
                int ticketCount = Integer.parseInt(ticketCountStr); // 转换为整数

                // 检查票数是否大于零
                if (ticketCount > 0) {
                    hasTickets = true; // 标记有票
                    String ticketType = item.get("ticketLabel"); // 获取票种
                    String totalPrice = calculateTotalPrice(ticketType, ticketCount); // 计算总价
                    count++;

                    // 根据票种计数器,将票务信息保存到相应的 StringBuilder 中
                    if (count == 1) {
                        ticketType1.append(ticketType);
                        ticketCount1.append(ticketCount);
                        totalPrice1.append(totalPrice);
                    } else if (count == 2) {
                        ticketType2.append(ticketType);
                        ticketCount2.append(ticketCount);
                        totalPrice2.append(totalPrice);
                    } else if (count == 3) {
                        ticketType3.append(ticketType);
                        ticketCount3.append(ticketCount);
                        totalPrice3.append(totalPrice);
                    } else if (count == 4) {
                        ticketType4.append(ticketType);
                        ticketCount4.append(ticketCount);
                        totalPrice4.append(totalPrice);
                    }
                }
            }

            // 如果有票
            if (hasTickets) {
                // 将订单数据插入到数据库
                buyHelper.insertOrderData(
                        mail,
                        orderId,
                        orderTime,
                        visitDate,
                        visitTime,
                        ticketType1.toString(),
                        ticketCount1.toString(),
                        totalPrice1.toString(),
                        ticketType2.toString(),
                        ticketCount2.toString(),
                        totalPrice2.toString(),
                        ticketType3.toString(),
                        ticketCount3.toString(),
                        totalPrice3.toString(),
                        ticketType4.toString(),
                        ticketCount4.toString(),
                        totalPrice4.toString(),
                        "待支付" // 设置订单状态为待支付
                );

                // 预约成功提示并跳转到订单页面
                Intent intent = new Intent(BuyActivity.this, OrderActivity.class);
                Toast.makeText(this, "预约成功!", Toast.LENGTH_SHORT).show();
                startActivity(intent);

            } else {
                // 没有选择票种提示
                Toast.makeText(this, "请选择需要的票种!", Toast.LENGTH_SHORT).show();
            }
        });
    }

4.游故宫、故宫建筑、故宫建筑详情页、参观须知

该页面可以实现跳转购票约展览、故宫建筑、地图导览页。 

1. **加载 JSON 数据**:调用 `loadJSONFromAsset()` 方法从资产中加载 JSON 数据,并将其存储在 `json` 变量中。如果 JSON 数据不为空,则继续处理。

2. **解析 JSON 数据**:
   - 创建 `Gson` 实例用于解析 JSON 数据。
   - 使用 `TypeToken` 定义 JSON 数据的类型(这里是 `List<UnitBean>`)。`TypeToken` 是 Gson 库中用于处理泛型的工具。
   - 调用 `Gson` 的 `fromJson` 方法,将 JSON 数据解析成 `unitList`(`List<UnitBean>` 类型)。

3. **配置 RecyclerView**:
   - 设置 `RecyclerView` 的布局管理器为 `GridLayoutManager`,并指定列数为 2,意味着 `RecyclerView` 将以网格形式显示数据,每行有 2 列。
   - 创建 `UnitAdapter` 实例并将其与 `RecyclerView` 关联。`UnitAdapter` 负责将 `unitList` 中的数据绑定到 `RecyclerView` 的视图上。

  • collect() 方法处理收藏和取消收藏逻辑,包括对用户进行登录提示。
  • back() 方法处理返回按钮的点击事件。
  • show() 方法负责显示和更新界面内容,包括加载图片和设置文本
  private void show() {
        // 从资产中加载 JSON 数据
        String json = loadJSONFromAsset();
        if (json != null) {
            // 创建 Gson 实例用于解析 JSON
            Gson gson = new Gson();
            // 定义用于解析的类型
            TypeToken<List<UnitBean>> token = new TypeToken<List<UnitBean>>() {
            };
            // 解析 JSON 数据并保存到 unitList
            unitList = gson.fromJson(json, token.getType());

            // 设置 RecyclerView 的布局管理器为 GridLayoutManager,设置列数为 2
            rv.setLayoutManager(new GridLayoutManager(this, 2)); // 2 列布局

            // 初始化适配器并与 RecyclerView 关联
            adapter = new UnitAdapter(this, unitList);
            rv.setAdapter(adapter);
        }
    }

5.看文物、数字文物库、文物详情页

1. **加载数据**:
   - 从应用的资产目录中读取 JSON 格式的数据文件。

2. **解析数据**:
   - 使用 Gson 库将 JSON 数据解析为 `List<FigureBean>` 对象,以便于在应用中使用。

3. **显示数据**:
   - 使用 `RecyclerView` 组件显示解析后的数据。
   - `RecyclerView` 的布局管理器设置为 `GridLayoutManager`,以 2 列网格的方式展示数据项。
   - 使用自定义适配器 `FigureAdapter` 将数据绑定到 `RecyclerView` 的视图中,以便在界面上展示数据列表。

   // 初始化显示数据的方法
    private void show() {
        // 从资产目录中加载 JSON 数据
        String json = loadJSONFromAsset();
        // 如果 JSON 数据不为空
        if (json != null) {
            // 创建 Gson 对象用于解析 JSON 数据
            Gson gson = new Gson();
            // 定义数据类型
            TypeToken<List<FigureBean>> token = new TypeToken<List<FigureBean>>() {
            };
            // 将 JSON 数据解析为 List<FigureBean> 对象,并赋值给 figureList
            figureList = gson.fromJson(json, token.getType()); // 保存原始数据到 figureList

            // 设置 RecyclerView 的布局管理器为 GridLayoutManager,显示为 2 列布局
            rv.setLayoutManager(new GridLayoutManager(this, 2)); // 2 列布局

            // 初始化适配器,并将 figureList 传递给适配器
            adapter = new FigureAdapter(this, figureList);
            // 设置 RecyclerView 的适配器
            rv.setAdapter(adapter);
        }
    }

1. **设置收藏按钮的点击事件** (`collect` 方法):
   - **检查用户登录状态**:判断用户的 `mail` 是否为空,确保用户已登录。
   - **处理收藏状态**:
     - 如果当前状态是“已收藏”,则执行取消收藏操作:
       - 调用 `collectHelper` 的 `deleteData` 方法删除收藏记录。
       - 根据删除结果,显示相应的提示信息,并更新按钮的文本和图标。
     - 如果当前状态是“收藏”,则执行收藏操作:
       - 调用 `collectHelper` 的 `insertData` 方法插入收藏记录。
       - 根据插入结果,显示相应的提示信息,并更新按钮的文本和图标。

2. **展示收藏状态和相关信息** (`show` 方法):
   - **获取并显示收藏状态**:
     - 从 `collectHelper` 获取收藏记录,检查收藏状态是否为“已收藏”。
     - 根据收藏状态更新 `tvCollect` 的文本和 `imgCollect` 的图标。
   - **加载和显示图片及相关信息**:
     - 使用 Glide 加载 `imgPath` 中的图片并显示在 `img` 组件上。
     - 设置 `tvName`、`tvNum`、`tvCategory` 和 `tvEra` 的文本内容为相应的数据。

 // 定义一个方法 collect(),用于设置收藏按钮的点击事件
    private void collect() {
        // 设置 llCollect 的点击事件监听器
        llCollect.setOnClickListener(v -> {
            // 检查 mail 是否为空,表示用户是否登录
            if (mail.isEmpty()) {
                // 如果 mail 为空,弹出提示框提醒用户先登录
                Toast.makeText(this, "请先进行登录!", Toast.LENGTH_SHORT).show();
            } else {
                // 获取 tvCollect 上的文本内容
                String s = tvCollect.getText().toString();
                // 如果文本内容是 "已收藏",则执行取消收藏的操作
                if (s.equals("已收藏")) {
                    // 调用 collectHelper 的 deleteData 方法,删除收藏记录
                    boolean b = collectHelper.deleteData(mail, name);
                    // 如果删除成功,弹出提示框并更新 UI
                    if (b) {
                        Toast.makeText(this, "已取消收藏!", Toast.LENGTH_SHORT).show();
                        // 更新 tvCollect 的文本为 "收藏"
                        tvCollect.setText("收藏");
                        // 更新 imgCollect 的图片资源为收藏的图标
                        imgCollect.setImageResource(R.drawable.collect);
                    } else {
                        // 如果删除失败,弹出提示框
                        Toast.makeText(this, "取消收藏失败!", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    // 如果文本内容是 "收藏",则执行收藏的操作
                    // 调用 collectHelper 的 insertData 方法,插入收藏记录
                    boolean collect = collectHelper.insertData(mail, "文物", "已收藏", imgPath, name, num, era, category, "", " ");
                    // 如果插入成功,弹出提示框并更新 UI
                    if (collect) {
                        Toast.makeText(this, "收藏成功!", Toast.LENGTH_SHORT).show();
                        // 更新 tvCollect 的文本为 "已收藏"
                        tvCollect.setText("已收藏");
                        // 更新 imgCollect 的图片资源为已收藏的图标
                        imgCollect.setImageResource(R.drawable.collectd);
                    } else {
                        // 如果插入失败,弹出提示框
                        Toast.makeText(this, "收藏失败!", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
    }

    // 定义一个方法 show(),用于展示收藏的状态和相关信息
    private void show() {
        // 从 collectHelper 获取收藏记录
        CollectBean collectBean = collectHelper.getCollect(mail, name);
        // 如果获取到收藏记录
        if (collectBean != null) {
            // 判断收藏记录的状态是否为 "已收藏"
            if (collectBean.getCollect().equals("已收藏")) {
                // 如果是 "已收藏",更新 UI 显示已收藏状态
                tvCollect.setText("已收藏");
                imgCollect.setImageResource(R.drawable.collectd);
            } else {
                // 如果不是 "已收藏",更新 UI 显示未收藏状态
                tvCollect.setText("收藏");
                imgCollect.setImageResource(R.drawable.collect);
            }
        } else {
            // 如果没有收藏记录,设置默认的未收藏状态
            tvCollect.setText("收藏");
            imgCollect.setImageResource(R.drawable.collect);
        }

        // 使用 Glide 加载 imgPath 中的图片并设置到 img 组件上
        Glide.with(this)
                .load(imgPath)
                .into(img);
        // 设置 tvName、tvNum、tvCategory 和 tvEra 的文本内容
        tvName.setText(name);
        tvNum.setText(num);
        tvCategory.setText(category);
        tvEra.setText(era);
    }

6.我的页面、我的收藏、我的订单

1. **TabLayout 设置**:
   - 添加了两个 Tab(选项卡),分别标记为“建筑”和“文物”。
   - 为 TabLayout 设置了选项卡选择监听器,根据用户选择的 Tab 执行不同的方法。

2. **数据加载方法**:
   - `JZData()` 方法:加载与“建筑”相关的数据,创建并设置相应的适配器(`CollectAdapter`),然后调用 `updateUI()` 方法更新界面。
   - `WWData()` 方法:加载与“文物”相关的数据,创建并设置相应的适配器(`FigureAdapter`),然后调用 `updateUI()` 方法更新界面。

3. **UI 更新方法**:
   - `updateUI()` 方法:根据数据列表是否为空来决定如何更新界面。如果数据列表为空,显示提示消息并显示占位视图;如果数据列表不为空,隐藏占位视图并设置 `RecyclerView` 的布局管理器和适配器,显示数据列表。

    private void setupTabLayout() {
        // 添加 Tab
        tablayout.addTab(tablayout.newTab().setText("建筑")); // 添加“建筑”Tab
        tablayout.addTab(tablayout.newTab().setText("文物")); // 添加“文物”Tab

        // 设置 Tab 选择监听器
        tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                // 获取被选中的 Tab 的文本
                String tabText = tab.getText().toString();
                // 判断选中的 Tab 文本,执行相应方法
                if (tabText.equals("建筑")) {
                    JZData(); // 如果是“建筑”Tab,调用 JZData 方法
                } else {
                    WWData(); // 否则,调用 WWData 方法
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                // 不需要处理此回调,暂时留空
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                // 不需要处理此回调,暂时留空
            }
        });
    }

    private void JZData() {
        // 获取“建筑”相关的数据
        List<CollectBean> collectBeans = collectHelper.getJZ(mail, "建筑");
        // 创建 CollectAdapter 适配器
        CollectAdapter collectAdapter = new CollectAdapter(this, collectBeans);
        // 更新 UI
        updateUI(collectBeans, collectAdapter, "您还没有收藏!");
    }

    private void WWData() {
        // 获取“文物”相关的数据
        List<FigureBean> figureBeans = collectHelper.getWW(mail, "文物");
        // 创建 FigureAdapter 适配器
        FigureAdapter figureAdapter = new FigureAdapter(this, figureBeans);
        // 更新 UI
        updateUI(figureBeans, figureAdapter, "您还没有收藏!");
    }

    private <T> void updateUI(List<T> dataList, RecyclerView.Adapter<?> adapter, String emptyMessage) {
        // 判断数据列表是否为空
        if (dataList.isEmpty()) {
            // 显示提示消息
            Toast.makeText(this, emptyMessage, Toast.LENGTH_SHORT).show();
            // 隐藏 RecyclerView
            rv.setVisibility(View.GONE);
            // 显示占位视图
            tvNoData.setVisibility(View.VISIBLE);
        } else {
            // 显示 RecyclerView
            rv.setVisibility(View.VISIBLE);
            // 隐藏占位视图
            tvNoData.setVisibility(View.GONE);
            // 设置 RecyclerView 的布局管理器为 GridLayoutManager,横排两个显示
            rv.setLayoutManager(new GridLayoutManager(this, 2));
            // 设置 RecyclerView 的适配器
            rv.setAdapter(adapter);
        }
    }

1. **TabLayout 设置**:
   - 添加了三个选项卡:`"全部"`、`"待支付"` 和 `"已支付"`。

2. **选项卡选择监听器**:
   - 当用户选择不同的选项卡时,触发 `onTabSelected` 方法,执行相应的操作:
     - 选择 `"全部"` 选项卡时,调用 `loadData()` 方法来加载所有订单数据。
     - 选择 `"待支付"` 或 `"已支付"` 选项卡时,根据选项卡的文本(状态)从数据库中获取相应状态的订单列表,并将这些订单数据反转,使得最新的订单显示在列表顶部。

3. **订单数据展示**:
   - 为 `"待支付"` 和 `"已支付"` 选项卡加载的数据创建 `OrderAdapter` 实例,并将订单数据传递给适配器,然后设置给 `ListView` 控件,展示订单列表。

**总结功能点**:
- 支持在 TabLayout 中切换不同的订单状态选项卡。
- 根据选中的选项卡加载不同的数据,`"全部"` 选项卡加载所有订单数据,其余选项卡根据订单状态筛选数据。
- 在 `ListView` 中展示订单列表,并确保最新的订单显示在顶部。

private void setupTabLayout() {
        // 向 TabLayout 添加 "全部" 选项卡
        tabLayout.addTab(tabLayout.newTab().setText("全部"));
        // 向 TabLayout 添加 "待支付" 选项卡
        tabLayout.addTab(tabLayout.newTab().setText("待支付"));
        // 向 TabLayout 添加 "已支付" 选项卡
        tabLayout.addTab(tabLayout.newTab().setText("已支付"));

        // 为 TabLayout 添加选项卡选中监听器
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                // 获取被选中的选项卡的文本
                String tabText = tab.getText().toString();
                // 根据选项卡的文本决定加载哪种数据
                if (tabText.equals("全部")) {
                    // 如果选中的是 "全部",加载所有订单数据
                    loadData();
                } else {
                    // 如果选中的是 "待支付" 或 "已支付",根据状态获取订单列表
                    List<OrderBean> orders = dbHelper.getOrdersByStatusAndMail(tabText, mail);

                    // 将订单列表反转,使得最新的订单显示在列表顶部
                    Collections.reverse(orders);

                    // 创建 OrderAdapter 实例,并将订单数据传递给适配器
                    OrderAdapter adapter = new OrderAdapter(OrderActivity.this, orders);
                    // 将适配器设置给 ListView 控件
                    lv.setAdapter(adapter);
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                // 选项卡未被选中时的操作,可以为空
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                // 选项卡被重新选中时的操作,可以为空
            }
        });
    }

7.账户设置、修改密码、修改用户名、退出

这个项目主要实现了用户信息更新功能,包含密码和用户名的修改。具体功能点总结如下:

1. **获取用户信息**:
   - 从 `SharedPreferences` 中获取用户的邮件地址,并将其设置到 `EditText` 控件 `etMail` 中。

2. **根据状态设置视图和按钮事件**:
   - 从 `Intent` 中获取 `state` 参数,根据其值("1" 或 "2")来确定要执行的操作:
     - **状态为 "1"**:调用 `setupPasswordUpdate()` 方法设置密码更新界面的视图和点击事件。
     - **状态为 "2"**:调用 `setupUsernameUpdate()` 方法设置用户名更新界面的视图和点击事件。

3. **密码更新功能** (`setupPasswordUpdate()` 方法):
   - 设置界面控件的提示文本,提示用户输入原密码和新密码。
   - 设置修改按钮的点击事件,执行以下操作:
     - 检查新密码长度是否在 6 到 16 个字符之间。
     - 验证原密码是否正确。如果正确,则尝试更新密码。
     - 更新密码成功后,跳转到主界面,并显示成功消息;失败时,显示失败消息。

4. **用户名更新功能** (`setupUsernameUpdate()` 方法):
   - 设置界面控件的提示文本,提示用户输入原用户名和新用户名。
   - 设置修改按钮的点击事件,执行以下操作:
     - 验证原用户名是否正确。如果正确,则尝试更新用户名。
     - 更新用户名成功后,清空输入框并显示成功消息;失败时,显示失败消息。

**总结**:
- 实现了基于用户状态的动态界面设置,支持密码和用户名的更新。
- 提供了用户输入验证和错误处理机制,以确保数据的正确性和用户体验。

  // 显示方法,根据不同的状态设置视图和按钮点击事件
    private void show() {
        // 从SharedPreferences中获取用户的邮件地址
        SharedPreferences sharedPreferences = getSharedPreferences("User", Context.MODE_PRIVATE);
        mail = sharedPreferences.getString("mail", "");
        // 将获取到的邮件地址设置到etMail(一个EditText控件)中
        etMail.setText(mail);

        // 获取Intent传递过来的“state”参数
        String state = getIntent().getStringExtra("state");

        // 根据“state”的值设置不同的视图和点击事件
        if (state.equals("1")) {
            setupPasswordUpdate(); // 如果state为"1",调用设置密码更新的函数
        } else if (state.equals("2")) {
            setupUsernameUpdate(); // 如果state为"2",调用设置用户名更新的函数
        }
    }

    // 设置密码更新的相关视图和点击事件
    private void setupPasswordUpdate() {
        // 设置原密码和新密码的提示文本
        tvOld.setText("原密码");
        etOld.setHint("请输入原密码");
        tvNew.setText("新密码");
        etNew.setHint("请输入新密码(6-16个字符)");

        // 设置修改按钮的点击事件
        btnModify.setOnClickListener(v -> {
            String oldPassword = etOld.getText().toString();
            String newPassword = etNew.getText().toString();

            // 检查新密码的长度是否在6到16个字符之间
            if (newPassword.length() < 6 || newPassword.length() > 16) {
                Toast.makeText(this, "密码长度应为6到16个字符!", Toast.LENGTH_SHORT).show();
                return;
            }

            // 验证原密码是否正确
            if (userHelper.isUserValid(mail, oldPassword)) {
                // 更新密码
                if (userHelper.updateUserPasswordByEmail(mail, newPassword)) {
                    showToast("更新成功");
                    navigateToMainActivity("3"); // 密码更新成功后,跳转到主界面
                } else {
                    showToast("更新失败");
                }
            } else {
                showToast("原密码错误!");
            }
        });
    }

    // 设置用户名更新的相关视图和点击事件
    private void setupUsernameUpdate() {
        // 设置原用户名和新用户名的提示文本
        tvOld.setText("原用户名");
        etOld.setHint("请输入原用户名");
        tvNew.setText("新用户名");
        etNew.setHint("请输入新用户名");

        // 设置修改按钮的点击事件
        btnModify.setOnClickListener(v -> {
            String oldUsername = etOld.getText().toString();
            String newUsername = etNew.getText().toString();

            // 验证原用户名是否正确
            if (userHelper.isUserValidByEmailAndUsername(mail, oldUsername)) {
                // 更新用户名
                if (userHelper.updateUsernameByEmail(mail, newUsername)) {
                    showToast("更新成功");
                    etOld.setText(""); // 清空输入框
                    etNew.setText("");
                } else {
                    showToast("更新失败");
                }
            } else {
                showToast("原用户名错误!");
            }
        });
    }

五、项目完整源码

👇👇👇👇👇快捷获取方式👇👇👇👇👇

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程乐学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值