feat(activity): 新增 BaseActivity 沉浸式基类和 HomeActivity 首页,统一 Activity 继承关系

- 新增 BaseActivity:继承 ComponentActivity,隐藏状态栏和导航栏,底部上滑可临时唤出导航栏
- 新增 HomeActivity(XML 版本)及对应布局 activity_home.xml,作为应用启动入口
- GoodsListActivity、FoodCollectionActivity、LocalImagePreviewActivity、PurchaseOrderActivity 统一改为继承 BaseActivity
- 更新 AndroidManifest.xml:HomeActivity 注册为启动入口

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 18:54:01 +08:00
co-authored by Claude Sonnet 4.6
parent d50b11c9aa
commit b6c7570efd
8 changed files with 301 additions and 9 deletions
+5 -1
View File
@@ -38,7 +38,7 @@
</receiver>
<activity
android:name=".MainActivity"
android:name=".activity.HomeActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:label="@string/app_name"
@@ -59,6 +59,10 @@
android:windowSoftInputMode="adjustPan" />
<activity android:name="com.sw.inbound.activity.LocalImagePreviewActivity" />
<activity android:name="com.sw.inbound.activity.PurchaseOrderActivity" />
<!-- 首页 ActivityXML 版本,对应 HomeScreen.kt Compose 版本) -->
<activity
android:name="com.sw.inbound.MainActivity"
android:screenOrientation="landscape" />
<!-- <activity-->
<!-- android:name=".InitActivity"-->
@@ -10,7 +10,7 @@ import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.ComponentActivity
import com.sw.inbound.base.BaseActivity
import androidx.activity.viewModels
import androidx.camera.view.PreviewView
import androidx.core.view.updateLayoutParams
@@ -68,7 +68,7 @@ import java.io.File
*/
@SuppressLint("NotifyDataSetChanged")
@AndroidEntryPoint
class FoodCollectionActivity : ComponentActivity() {
class FoodCollectionActivity : BaseActivity() {
companion object {
const val TAG = "FoodCollectionActivity"
@@ -9,7 +9,7 @@ import android.text.style.ForegroundColorSpan
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.ComponentActivity
import com.sw.inbound.base.BaseActivity
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.camera.view.PreviewView
@@ -70,7 +70,7 @@ import kotlin.math.min
typealias RecognizeCallback = (List<SearchGoodsInfo.Record>) -> Unit
@AndroidEntryPoint
abstract class GoodsListActivity : ComponentActivity() {
abstract class GoodsListActivity : BaseActivity() {
companion object {
private const val TAG = "GoodsListActivity"
@@ -0,0 +1,131 @@
package com.sw.inbound.activity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.activity.viewModels
import com.sw.inbound.base.BaseActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.sw.inbound.databinding.ActivityHomeBinding
import com.sw.inbound.model.response.User
import com.sw.inbound.objbox.FoodModule
import com.sw.inbound.sdk.SensorScaleUtils
import com.sw.inbound.utils.DateTimeUtils
import com.sw.inbound.utils.ThreadUtils
import com.sw.inbound.utils.ext.gone
import com.sw.inbound.utils.ext.startActivity
import com.sw.inbound.utils.ext.visible
import com.sw.inbound.viewmodel.UserViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
/**
* 首页 ActivityXML 版本)
* 对应原 HomeScreen.kt Compose 版本,原文件保留不动
* 功能:展示标题栏(含实时时间或用户信息)和两个功能入口(采购单入库、自采入库)
*/
@AndroidEntryPoint
class HomeActivity : BaseActivity() {
private lateinit var binding: ActivityHomeBinding
/** 用于获取用户信息的 ViewModel */
private val viewModel: UserViewModel by viewModels()
/** 每秒刷新当前时间的 Handler */
private val handler = Handler(Looper.getMainLooper())
/** 时间刷新任务,每 1 秒更新一次标题栏右侧时间文字 */
private val timeRunnable = object : Runnable {
override fun run() {
binding.tvTime.text = DateTimeUtils.getChineseDateString()
handler.postDelayed(this, 1000)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)
initViews()
observeUser()
SensorScaleUtils.startScale(autoScale = true)
lifecycleScope.launch {
FoodModule.init(this@HomeActivity)
}
}
override fun onDestroy() {
SensorScaleUtils.closeScale()
ThreadUtils.release()
super.onDestroy()
}
/**
* 初始化各控件的点击事件
*/
private fun initViews() {
// 标题点击:跳转菜品采集页面
binding.tvTitle.setOnClickListener {
startActivity<FoodCollectionActivity>()
}
// 采购单入库入口
binding.ivOrderPurchase.setOnClickListener {
startActivity<PurchaseOrderActivity>()
}
// 自采入库入口,传入非采购单标志
binding.ivOrderSelfProcurement.setOnClickListener {
startActivity<SelfProcurementActivity> {
putExtra(GoodsListActivity.IS_RECEIPT_PAGE, false)
}
}
}
/**
* 观察用户登录状态,动态切换标题栏右侧显示内容:
* - 已登录:显示用户名 + 退出图标
* - 未登录:显示实时时间
*/
private fun observeUser() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.user.collect { user ->
updateUserView(user)
}
}
}
}
/**
* 根据登录状态切换标题栏右侧 UI
* @param user 当前用户信息,为 null 表示未登录
*/
private fun updateUserView(user: User?) {
if (user != null) {
// 已登录:显示用户名和退出图标,隐藏时间
binding.tvTime.gone()
binding.llUserInfo.visible()
binding.tvUserName.text = user.name ?: "用户"
} else {
// 未登录:显示实时时间,隐藏用户信息
binding.llUserInfo.gone()
binding.tvTime.visible()
}
}
override fun onResume() {
super.onResume()
// 页面可见时启动时间刷新
handler.post(timeRunnable)
}
override fun onPause() {
super.onPause()
// 页面不可见时停止刷新,避免内存泄漏
handler.removeCallbacks(timeRunnable)
}
}
@@ -4,7 +4,7 @@ import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.activity.ComponentActivity
import com.sw.inbound.base.BaseActivity
import androidx.recyclerview.widget.GridLayoutManager
import coil.load
import com.chad.library.adapter4.BaseQuickAdapter
@@ -15,7 +15,7 @@ import com.sw.inbound.dialog.Loading
import com.sw.inbound.utils.ext.copyText
import java.io.File
class LocalImagePreviewActivity : ComponentActivity() {
class LocalImagePreviewActivity : BaseActivity() {
private lateinit var binding: ActivityLocalImagePreviewBinding
@@ -2,7 +2,7 @@ package com.sw.inbound.activity
import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import com.sw.inbound.base.BaseActivity
import androidx.activity.viewModels
import androidx.compose.runtime.collectAsState
import androidx.lifecycle.lifecycleScope
@@ -24,7 +24,7 @@ import kotlinx.coroutines.launch
* 采购单列表
*/
@AndroidEntryPoint
class PurchaseOrderActivity : ComponentActivity() {
class PurchaseOrderActivity : BaseActivity() {
private var list = mutableListOf<SupplierInfo>()
private val adapter by lazy {
@@ -0,0 +1,51 @@
package com.sw.inbound.base
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
/**
* 所有 Activity 的基类
* - 继承 ComponentActivity,保持与项目其他 Activity 一致
* - 自动隐藏状态栏和导航栏,实现全屏沉浸式体验
* - 在屏幕底部上滑时可临时唤出导航栏,松手后自动收回
*/
abstract class BaseActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
hideSystemBars()
}
/**
* 窗口焦点变化时回调
* 场景:弹出 Dialog 后焦点丢失,Dialog 消失后焦点恢复,此时需重新隐藏系统栏,
* 避免系统栏在 Dialog 关闭后意外"复活"
*/
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
hideSystemBars()
}
}
/**
* 隐藏状态栏和导航栏
* 使用 WindowInsetsControllerCompatAndroidx 推荐方式,向下兼容性好)
* - 状态栏:完全隐藏
* - 导航栏:完全隐藏,底部上滑时临时出现,松手后自动收回(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
*/
private fun hideSystemBars() {
// 允许布局延伸到系统栏区域(edge-to-edge),避免内容被系统栏遮挡
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).apply {
// 同时隐藏状态栏和导航栏
hide(WindowInsetsCompat.Type.systemBars())
// 底部上滑时临时显示导航栏,松手后自动隐藏(沉浸式 Sticky 模式)
systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
}
+106
View File
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg"
android:orientation="vertical">
<!-- 标题栏区域,与 TopTitleBar Compose 组件对应 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="60dp"
android:paddingEnd="60dp"
android:paddingTop="22dp">
<!-- 标题文字,点击可跳转菜品采集页面 -->
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="出入库管理"
android:textColor="@color/title"
android:textSize="36sp"
android:textStyle="bold" />
<!-- 占位弹性空间 -->
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<!-- 当前时间文字(用户未登录时显示) -->
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="24sp"
android:visibility="visible" />
<!-- 用户信息区(已登录时显示,未登录隐藏) -->
<LinearLayout
android:id="@+id/llUserInfo"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:id="@+id/tvUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="24sp" />
<Space
android:layout_width="21dp"
android:layout_height="1dp" />
<!-- 退出登录图标 -->
<ImageView
android:id="@+id/ivLogout"
android:layout_width="60dp"
android:layout_height="60dp"
android:contentDescription="退出"
android:src="@mipmap/ic_logout" />
</LinearLayout>
</LinearLayout>
<!-- 功能入口区域,水平居中排列两个入口图标 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<!-- 采购单入库入口 -->
<ImageView
android:id="@+id/ivOrderPurchase"
android:layout_width="595dp"
android:layout_height="477dp"
android:contentDescription="采购单入库"
android:src="@mipmap/ic_order_purchase" />
<Space
android:layout_width="15dp"
android:layout_height="1dp" />
<!-- 自采入库入口 -->
<ImageView
android:id="@+id/ivOrderSelfProcurement"
android:layout_width="595dp"
android:layout_height="477dp"
android:contentDescription="自采入库"
android:src="@mipmap/ic_order_self_procurement" />
</LinearLayout>
</LinearLayout>