个人作业Android学习系统开发日志四
Android实现:
WeekGoals:
entity:
package com.example.learningmanagement.entity
data class WeekGoals(
val id: Int,
val weekNumber: Int,
val title: String,
val content: String,
val userId: Int
)
adapter:
package com.example.learningmanagement.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.learningmanagement.entity.WeekGoals
import com.example.learningmanagement.databinding.ItemWeekGoalBinding
class WeekGoalsAdapter :
ListAdapter<WeekGoals, WeekGoalsAdapter.ViewHolder>(WeekGoalsDiffCallback()) {
class ViewHolder(private val binding: ItemWeekGoalBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(weekGoal: WeekGoals) {
binding.tvTitle.text = weekGoal.title
binding.tvContent.text = weekGoal.content
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemWeekGoalBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
}
class WeekGoalsDiffCallback : DiffUtil.ItemCallback<WeekGoals>() {
override fun areItemsTheSame(oldItem: WeekGoals, newItem: WeekGoals) = oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: WeekGoals, newItem: WeekGoals) = oldItem == newItem
}
service:
package com.example.learningmanagement.service
import com.example.learningmanagement.entity.ApiResponse
import com.example.learningmanagement.entity.WeekGoals
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
interface WeekGoalsService {
@GET("weekGoals/selectAll/{userId}")
suspend fun getWeekGoals(@Path("userId") userId: String): ApiResponse<List<WeekGoals>>
@POST("weekGoals/add")
suspend fun addWeekGoal(@Body weekGoal: WeekGoals): ApiResponse<WeekGoals>
@DELETE("weekGoals/deleteById/{id}")
suspend fun deleteWeekGoal(@Path("id") id: Int): ApiResponse<String>
}
fragment:
package com.example.learningmanagement.ui.fragment
import android.content.Context
import android.os.Bundle
import android.view.GestureDetector
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.learningmanagement.adapter.WeekGoalsAdapter
import com.example.learningmanagement.databinding.FragmentWeekGoalsBinding
import com.example.learningmanagement.network.ServiceCreater
import com.example.learningmanagement.service.WeekGoalsService
import com.example.learningmanagement.ui.MainActivity
import com.example.learningmanagement.utils.PrefsHelper
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
import kotlinx.coroutines.isActive
import kotlin.math.abs
class WeekGoalsFragment : Fragment() {
private var _binding: FragmentWeekGoalsBinding? = null
private val binding get() = _binding!!
private val weekGoalsService = ServiceCreater.create<WeekGoalsService>()
private val weekGoalsAdapter = WeekGoalsAdapter()
private lateinit var prefs: PrefsHelper
// 添加滑动相关变量
private lateinit var gestureDetector: GestureDetector
private var allGoals = listOf<com.example.learningmanagement.entity.WeekGoals>()
private var currentPosition = 0
override fun onAttach(context: Context) {
super.onAttach(context)
prefs = PrefsHelper(context)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWeekGoalsBinding.inflate(inflater, container, false)
// 初始化手势检测器
gestureDetector =
GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
if (e1 == null) return false
val diffX = e2.x - e1.x
val diffY = e2.y - e1.y
// 确保是水平滑动而不是垂直滑动
if (abs(diffX) > abs(diffY)) {
if (diffX > 0) {
// 向右滑动,显示上一条数据
showPreviousGoal()
} else {
// 向左滑动,显示下一条数据
showNextGoal()
}
return true
}
return false
}
})
// 设置触摸监听器
binding.root.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(event)
false
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
loadWeekGoals()
}
private fun setupRecyclerView() {
binding.rvWeekGoals.apply {
layoutManager = LinearLayoutManager(context)
adapter = weekGoalsAdapter
}
}
// 显示上一条数据
private fun showPreviousGoal() {
if (allGoals.isEmpty()) return
if (currentPosition > 0) {
currentPosition--
updateDisplay()
} else {
showToast("已经是第一条数据")
}
}
// 显示下一条数据
private fun showNextGoal() {
if (allGoals.isEmpty()) return
if (currentPosition < allGoals.size - 1) {
currentPosition++
updateDisplay()
} else {
showToast("已经是最后一条数据")
}
}
// 更新显示
private fun updateDisplay() {
if (allGoals.isEmpty() || !isAdded || _binding == null) return
val currentGoal = allGoals[currentPosition]
// 更新RecyclerView显示当前选中的目标
weekGoalsAdapter.submitList(listOf(currentGoal))
// 更新主活动中的周数标题
(activity as? MainActivity)?.updateWeekTitle("第${currentGoal.weekNumber}周")
}
private fun loadWeekGoals() {
if (!isAdded) return
lifecycleScope.launch {
try {
val userId = prefs.getUserId()
userId?.let { id ->
try {
if (!isActive) return@launch
val response = weekGoalsService.getWeekGoals(id)
if (!isActive || !isAdded || _binding == null) return@launch
if (response.code == "200") {
response.data?.let { goals ->
if (goals.isNotEmpty()) {
// 保存所有目标数据
allGoals = goals.sortedByDescending { it.weekNumber }
// 默认显示最新的数据(第一条)
currentPosition = 0
updateDisplay()
// 显示RecyclerView
binding.rvWeekGoals.visibility = View.VISIBLE
binding.tvEmptyData.visibility = View.GONE
} else {
allGoals = emptyList()
weekGoalsAdapter.submitList(emptyList())
showEmptyView()
}
} ?: run {
allGoals = emptyList()
weekGoalsAdapter.submitList(emptyList())
showEmptyView()
}
} else {
showToast("获取数据失败: ${response.msg}")
showEmptyView()
}
} catch (e: CancellationException) {
android.util.Log.d("WeekGoalsFragment", "协程已取消")
} catch (e: Exception) {
if (!isActive || !isAdded || _binding == null) return@launch
val errorMessage = "网络请求错误: ${e.javaClass.simpleName} - ${e.message}"
showToast(errorMessage)
android.util.Log.e("WeekGoalsFragment", errorMessage, e)
showEmptyView()
}
} ?: run {
if (!isActive || !isAdded || _binding == null) return@launch
showToast("用户未登录")
showEmptyView()
}
} catch (e: CancellationException) {
android.util.Log.d("WeekGoalsFragment", "协程已取消")
} catch (e: Exception) {
if (!isActive || !isAdded || _binding == null) return@launch
val errorMessage = "加载失败: ${e.javaClass.simpleName} - ${e.message}"
showToast(errorMessage)
android.util.Log.e("WeekGoalsFragment", errorMessage, e)
showEmptyView()
}
}
}
private fun showToast(message: String) {
if (isAdded && activity != null) {
activity?.let {
Toast.makeText(it, message, Toast.LENGTH_SHORT).show()
}
}
}
private fun showEmptyView() {
if (!isAdded || _binding == null) return
(activity as? MainActivity)?.updateWeekTitle("周目标")
binding.tvEmptyData.visibility = View.VISIBLE
binding.rvWeekGoals.visibility = View.GONE
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
fun refreshData() {
if (isAdded && _binding != null) {
loadWeekGoals()
}
}
// 在类中添加删除方法
fun deleteCurrentGoal() {
if (allGoals.isEmpty() || currentPosition < 0 || currentPosition >= allGoals.size) {
showToast("没有可删除的数据")
return
}
val currentGoal = allGoals[currentPosition]
// 显示确认对话框
context?.let { ctx ->
androidx.appcompat.app.AlertDialog.Builder(ctx)
.setTitle("确认删除")
.setMessage("确定要删除第${currentGoal.weekNumber}周的目标吗?")
.setPositiveButton("确定") { _, _ ->
performDelete(currentGoal.id)
}
.setNegativeButton("取消", null)
.show()
}
}
// 执行删除操作
private fun performDelete(goalId: Int) {
lifecycleScope.launch {
try {
if (!isActive || !isAdded || _binding == null) return@launch
// 显示加载提示
showToast("正在删除...")
val response = weekGoalsService.deleteWeekGoal(goalId)
if (!isActive || !isAdded || _binding == null) return@launch
if (response.code == "200") {
showToast("删除成功")
// 从列表中移除已删除的项
val newList = allGoals.toMutableList()
newList.removeAt(currentPosition)
allGoals = newList
// 调整当前位置
if (allGoals.isEmpty()) {
// 如果删除后没有数据了
currentPosition = -1
showEmptyView()
} else {
// 如果删除的是最后一项,则显示新的最后一项
if (currentPosition >= allGoals.size) {
currentPosition = allGoals.size - 1
}
updateDisplay()
}
} else {
showToast("删除失败: ${response.msg}")
}
} catch (e: CancellationException) {
android.util.Log.d("WeekGoalsFragment", "协程已取消")
} catch (e: Exception) {
if (!isActive || !isAdded || _binding == null) return@launch
val errorMessage = "删除失败: ${e.javaClass.simpleName} - ${e.message}"
showToast(errorMessage)
android.util.Log.e("WeekGoalsFragment", errorMessage, e)
}
}
}
}
xml:
<?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">
<!-- 顶部标题栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/pink_500"
android:gravity="center_vertical"
android:paddingHorizontal="16dp">
<!-- 周数标题 -->
<TextView
android:id="@+id/tvWeekTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第15周"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"/>
<!-- 空白占位 -->
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<!-- 操作按钮组 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<!-- 删除按钮 -->
<ImageButton
android:id="@+id/btnDelete"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_delete_white"
android:contentDescription="删除"
app:tint="@color/white" />
<!-- 修改按钮 -->
<ImageButton
android:id="@+id/btnEdit"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_edit_white"
android:contentDescription="修改"
android:layout_marginStart="8dp"
app:tint="@color/white" />
<!-- 添加按钮 -->
<ImageButton
android:id="@+id/btnAdd"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_add_white"
android:contentDescription="添加"
android:layout_marginStart="8dp"
app:tint="@color/white" />
</LinearLayout>
</LinearLayout>
<!-- 内容区域 -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@drawable/bg_pink_gradient"/>
<!-- 底部导航 -->
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:background="@color/pink_500"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemHorizontalTranslationEnabled="false"
app:labelVisibilityMode="labeled"
app:menu="@menu/bottom_nav_menu" />
</LinearLayout>
<?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="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/etWeekNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="周数"
android:inputType="number"
android:maxLines="1"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/etTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="标题"
android:maxLines="1"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/etContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="内容"
android:minLines="3"
android:gravity="top|start"
android:inputType="textMultiLine"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvWeekGoals"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
<TextView
android:id="@+id/tvEmptyData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="暂无数据"
android:textSize="18sp"
android:textColor="#757575"
android:visibility="gone" />
</FrameLayout>

浙公网安备 33010602011771号