本文主要是介绍基于 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"><Buttonandroid: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();// 结束当前Activityfinish();} 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跳转到RegisterActivityIntent intent = new Intent(LoginActivity.this, RegisterActivity.class);// 启动RegisterActivitystartActivity(intent);});}// 定义一个私有方法back,用于处理返回操作private void back() {// 为imgBack(可能是一个ImageView控件)设置点击事件监听器imgBack.setOnClickListener(v -> {// 结束当前Activityfinish();});}// 定义一个私有方法forgot,用于处理忘记密码页面的跳转private void forgot() {// 为tvForget(可能是一个TextView控件)设置点击事件监听器tvForget.setOnClickListener(v -> {// 创建一个Intent,用于从当前Activity跳转到ForgotPasswordActivityIntent intent = new Intent(LoginActivity.this, ForgotPasswordActivity.class);// 启动ForgotPasswordActivitystartActivity(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; // 退出方法}// 获取选中的参观时间单选按钮的 IDint selectedId = rb.getCheckedRadioButtonId();// 根据 ID 查找选中的单选按钮RadioButton selectedRadioButton = findViewById(selectedId);// 检查是否选择了参观时间if (selectedRadioButton == null) {Toast.makeText(this, "请选择参观时间", Toast.LENGTH_SHORT).show();return; // 退出方法}// 获取选中的参观时间String visitTime = selectedRadioButton.getText().toString();// 生成订单 IDString 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 实例用于解析 JSONGson gson = new Gson();// 定义用于解析的类型TypeToken<List<UnitBean>> token = new TypeToken<List<UnitBean>>() {};// 解析 JSON 数据并保存到 unitListunitList = gson.fromJson(json, token.getType());// 设置 RecyclerView 的布局管理器为 GridLayoutManager,设置列数为 2rv.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> 对象,并赋值给 figureListfigureList = 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);// 如果删除成功,弹出提示框并更新 UIif (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, "", " ");// 如果插入成功,弹出提示框并更新 UIif (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() {// 添加 Tabtablayout.addTab(tablayout.newTab().setText("建筑")); // 添加“建筑”Tabtablayout.addTab(tablayout.newTab().setText("文物")); // 添加“文物”Tab// 设置 Tab 选择监听器tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {@Overridepublic void onTabSelected(TabLayout.Tab tab) {// 获取被选中的 Tab 的文本String tabText = tab.getText().toString();// 判断选中的 Tab 文本,执行相应方法if (tabText.equals("建筑")) {JZData(); // 如果是“建筑”Tab,调用 JZData 方法} else {WWData(); // 否则,调用 WWData 方法}}@Overridepublic void onTabUnselected(TabLayout.Tab tab) {// 不需要处理此回调,暂时留空}@Overridepublic void onTabReselected(TabLayout.Tab tab) {// 不需要处理此回调,暂时留空}});}private void JZData() {// 获取“建筑”相关的数据List<CollectBean> collectBeans = collectHelper.getJZ(mail, "建筑");// 创建 CollectAdapter 适配器CollectAdapter collectAdapter = new CollectAdapter(this, collectBeans);// 更新 UIupdateUI(collectBeans, collectAdapter, "您还没有收藏!");}private void WWData() {// 获取“文物”相关的数据List<FigureBean> figureBeans = collectHelper.getWW(mail, "文物");// 创建 FigureAdapter 适配器FigureAdapter figureAdapter = new FigureAdapter(this, figureBeans);// 更新 UIupdateUI(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();// 隐藏 RecyclerViewrv.setVisibility(View.GONE);// 显示占位视图tvNoData.setVisibility(View.VISIBLE);} else {// 显示 RecyclerViewrv.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() {@Overridepublic 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);}}@Overridepublic void onTabUnselected(TabLayout.Tab tab) {// 选项卡未被选中时的操作,可以为空}@Overridepublic 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("原用户名错误!");}});}
五、项目完整源码
👇👇👇👇👇快捷获取方式👇👇👇👇👇
这篇关于基于 Android Studio 仿故宫博物院(馆)App--原创的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!