From d166fa86711d9348ac987ba87715e986a3b1a27b Mon Sep 17 00:00:00 2001
From: tj <1378534974@qq.com>
Date: 星期五, 18 四月 2025 15:20:23 +0800
Subject: [PATCH] 1.日历热力图修改
---
app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt | 433 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 415 insertions(+), 18 deletions(-)
diff --git a/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt b/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
index b689d58..5aa4f28 100644
--- a/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
+++ b/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
@@ -1,37 +1,40 @@
package com.example.firstapp.ui.dashboard
-import com.example.firstapp.R
+import android.graphics.Color
import android.os.Bundle
+import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.webkit.WebView
+import android.widget.GridLayout
+import android.widget.HorizontalScrollView
+import android.widget.LinearLayout
import android.widget.TextView
+import android.widget.Toast
+import androidx.cardview.widget.CardView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
-import com.example.firstapp.databinding.FragmentDashboardBinding
-import com.google.android.material.tabs.TabLayout
+import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
+import com.example.firstapp.R
import com.example.firstapp.adapter.PackageAdapter
+import com.example.firstapp.database.response.UserInfo
+import com.example.firstapp.database.service.RetrofitClient
+import com.example.firstapp.databinding.FragmentDashboardBinding
+import com.example.firstapp.model.DailyStat
+import com.example.firstapp.utils.PreferencesManager
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.*
import com.github.mikephil.charting.formatter.ValueFormatter
-import java.util.*
-import java.text.SimpleDateFormat
-import android.graphics.Color
-import android.view.Gravity
-import android.widget.GridLayout
-import android.widget.LinearLayout
-import android.widget.Toast
-import androidx.cardview.widget.CardView
-import androidx.lifecycle.lifecycleScope
-import com.example.firstapp.database.response.UserInfo
-import com.example.firstapp.database.service.RetrofitClient
-import com.example.firstapp.model.DailyStat
-import com.example.firstapp.utils.PreferencesManager
+import com.google.android.material.tabs.TabLayout
import kotlinx.coroutines.launch
+import java.text.SimpleDateFormat
+import java.util.*
+
class DashboardFragment : Fragment() {
@@ -57,6 +60,7 @@
}
private val viewModel: DashboardViewModel by viewModels()
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -74,6 +78,14 @@
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
+// val webView: WebView = binding.layoutWeekStats.webView
+// val webSettings = webView.settings
+// webSettings.javaScriptEnabled = true // 启用 JavaScript
+//
+//
+// // 加载本地的 HTML 文件
+// webView.loadUrl("file:///android_asset/calendar-heatmap.html")
//渲染包裹列表
setupRecyclerView()
@@ -763,7 +775,242 @@
heatmapView.visibility = View.GONE
}
+
+
+ // 用于创建图例
+ private fun createLegend(): LinearLayout {
+ val legendLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.HORIZONTAL
+ gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ setPadding(8, 16, 8, 0)
+ }
+
+ val labelLow = TextView(context).apply {
+ text = "少"
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+ legendLayout.addView(labelLow)
+
+ val legendLevels = listOf(0, 5, 10, 15, 20)
+ legendLevels.forEach { level ->
+ val colorBox = View(context).apply {
+ setBackgroundColor(getHeatmapColor(level))
+ val size = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ layoutParams = LinearLayout.LayoutParams(size, size).apply {
+ marginEnd = 4
+ }
+ }
+
+ val label = TextView(context).apply {
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+
+ legendLayout.addView(colorBox)
+ legendLayout.addView(label)
+ }
+
+ val labelHigh = TextView(context).apply {
+ text = "多"
+ textSize = 10f
+ setPadding(8, 0, 0, 0)
+ }
+ legendLayout.addView(labelHigh)
+
+ return legendLayout
+ }
+
private fun updateHeatmapData() {
+ viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
+ if (stats.isEmpty()) return@observe
+
+ val heatmapMatrix = Array(7) { IntArray(52) }
+ stats.forEach { stat ->
+ val week = stat.weekOfYear - 1
+ val dayOfWeek = stat.dayOfWeek - 1
+ if (week in 0..51 && dayOfWeek in 0..6) {
+ heatmapMatrix[dayOfWeek][week] = stat.count
+ }
+ }
+
+ binding.layoutWeekStats.heatmapYearly.apply {
+ removeAllViews()
+
+ // 外层父布局:水平 LinearLayout,左固定周标签,右为横向滚动热力图
+ val outerLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.HORIZONTAL
+ }
+
+ // 左侧星期标签列
+ val dayLabelLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.VERTICAL
+ val dayLabels = arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日")
+ // 顶部空白占位
+ addView(TextView(context).apply {
+ text = ""
+ textSize = 20f
+ height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ })
+ dayLabels.forEach { label ->
+ val textView = TextView(context).apply {
+ text = label
+ textSize = 10f
+ height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ setPadding(4, 0, 4, 0)
+ }
+ addView(textView)
+ }
+ }
+
+ // 右侧滚动部分
+ val scrollView = HorizontalScrollView(context).apply {
+ isHorizontalScrollBarEnabled = false
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ val scrollContentLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.VERTICAL
+ }
+
+ val gridLayout = GridLayout(context).apply {
+ rowCount = 8
+ columnCount = 52
+ }
+
+ // 添加月份标签(估算)
+ val months = arrayOf(
+ "1月", "2月", "3月", "4月", "5月", "6月",
+ "7月", "8月", "9月", "10月", "11月", "12月"
+ )
+ /* months.forEachIndexed { index, month ->
+ val label = TextView(context).apply {
+ text = month
+ textSize = 10f
+ setPadding(10, 0, 8, 4)
+ val weekPosition = (index * 4.3).toInt()
+ layoutParams = GridLayout.LayoutParams().apply {
+ columnSpec = GridLayout.spec(weekPosition)
+ rowSpec = GridLayout.spec(0)
+ }
+ }
+ gridLayout.addView(label)
+ }*/
+ months.forEachIndexed { index, month ->
+ val label = TextView(context).apply {
+ text = month
+ textSize = 10f
+ setPadding(10, 0, 8, 4)
+
+ val weekPosition = (index * 4.3).toInt()
+ val span = 4 // 控制跨列范围
+ layoutParams = GridLayout.LayoutParams().apply {
+ columnSpec = GridLayout.spec(weekPosition, span, GridLayout.CENTER)
+ rowSpec = GridLayout.spec(0)
+ }
+ }
+ gridLayout.addView(label)
+ }
+
+ // 添加热力格子
+ for (day in 0..6) {
+ for (week in 0..51) {
+ val count = heatmapMatrix[day][week]
+ val cell = View(context).apply {
+ layoutParams = GridLayout.LayoutParams().apply {
+ width = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ columnSpec = GridLayout.spec(week)
+ rowSpec = GridLayout.spec(day + 1)
+ setMargins(1, 1, 1, 1)
+ }
+ setBackgroundColor(getHeatmapColor(count))
+ }
+ gridLayout.addView(cell)
+ }
+ }
+
+ scrollContentLayout.addView(gridLayout)
+ scrollView.addView(scrollContentLayout)
+
+ // 添加两个主要部分到外层布局
+ outerLayout.addView(dayLabelLayout)
+ outerLayout.addView(scrollView)
+
+ // 图例
+ val legendLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.HORIZONTAL
+ gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ setPadding(8, 16, 8, 0)
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ val labelLow = TextView(context).apply {
+ text = "少"
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+ legendLayout.addView(labelLow)
+
+ val legendLevels = listOf(0, 5, 10, 15, 20)
+ legendLevels.forEach { level ->
+ val colorBox = View(context).apply {
+ setBackgroundColor(getHeatmapColor(level))
+ val size = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ layoutParams = LinearLayout.LayoutParams(size, size).apply {
+ marginEnd = 4
+ }
+ }
+
+ val label = TextView(context).apply {
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+
+ legendLayout.addView(colorBox)
+ legendLayout.addView(label)
+ }
+
+ val labelHigh = TextView(context).apply {
+ text = "多"
+ textSize = 10f
+ setPadding(8, 0, 0, 0)
+ }
+ legendLayout.addView(labelHigh)
+
+ // 总容器垂直布局:热力图 + 图例
+ val container = LinearLayout(context).apply {
+ orientation = LinearLayout.VERTICAL
+ addView(outerLayout)
+ addView(legendLayout)
+ }
+
+// addView(container)
+
+ // 设置外部 margin
+ val params = LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ).apply {
+ setMargins(16, 16, 16, 16) // 左、上、右、下的 margin,单位是像素
+ }
+
+ // 添加到父布局并应用 margin
+ addView(container, params)
+
+ }
+ }
+ }
+
+
+
+ private fun updateHeatmapData_a() {
viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
if (stats.isEmpty()) return@observe
@@ -789,8 +1036,10 @@
}
// 添加月份标签
- val months = arrayOf("1月", "2月", "3月", "4月", "5月", "6月",
- "7月", "8月", "9月", "10月", "11月", "12月")
+ val months = arrayOf(
+ "1月", "2月", "3月", "4月", "5月", "6月",
+ "7月", "8月", "9月", "10月", "11月", "12月"
+ )
months.forEachIndexed { index, month ->
val label = TextView(context).apply {
text = month
@@ -898,6 +1147,154 @@
}
}
+ private fun updateHeatmapData_aaa() {
+ viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
+ if (stats.isEmpty()) return@observe
+
+ // 创建52周x7天的数据矩阵
+ val heatmapMatrix = Array(7) { IntArray(52) }
+
+ // 填充数据
+ stats.forEach { stat ->
+ val week = stat.weekOfYear - 1 // 0-51
+ val dayOfWeek = stat.dayOfWeek - 1 // 0-6
+ if (week in 0..51 && dayOfWeek in 0..6) {
+ heatmapMatrix[dayOfWeek][week] = stat.count
+ }
+ }
+
+ // 更新UI
+ binding.layoutWeekStats.heatmapYearly.apply {
+ removeAllViews()
+
+ val gridLayout = GridLayout(context).apply {
+ rowCount = 8 // 1行月份 + 7行星期
+ columnCount = 53 // 1列星期 + 52列周数
+ }
+
+ // 添加月份标签
+ val months = arrayOf("1月", "2月", "3月", "4月", "5月", "6月",
+ "7月", "8月", "9月", "10月", "11月", "12月")
+ months.forEachIndexed { index, month ->
+ val label = TextView(context).apply {
+ text = month
+ textSize = 10f
+ setPadding(0, 0, 8, 4)
+ val weekPosition = (index * 4.3).toInt() // 估算月份起始位置
+ layoutParams = GridLayout.LayoutParams().apply {
+ columnSpec = GridLayout.spec(weekPosition + 1)
+ rowSpec = GridLayout.spec(0)
+ }
+ }
+ gridLayout.addView(label)
+ }
+
+ // 添加星期标签
+ val dayLabels = arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日")
+ dayLabels.forEachIndexed { index, label ->
+ val textView = TextView(context).apply {
+ text = label
+ textSize = 10f
+ setPadding(4, 0, 8, 0)
+ layoutParams = GridLayout.LayoutParams().apply {
+ columnSpec = GridLayout.spec(0)
+ rowSpec = GridLayout.spec(index + 1)
+ }
+ }
+ gridLayout.addView(textView)
+ }
+
+ // 添加热力图单元格
+ for (day in 0..6) {
+ for (week in 0..51) {
+ val count = heatmapMatrix[day][week]
+ val cell = View(context).apply {
+ layoutParams = GridLayout.LayoutParams().apply {
+ width = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ columnSpec = GridLayout.spec(week + 1)
+ rowSpec = GridLayout.spec(day + 1)
+ setMargins(1, 1, 1, 1)
+ }
+ setBackgroundColor(getHeatmapColor(count))
+ }
+ gridLayout.addView(cell)
+ }
+ }
+
+ // ✅ 把 gridLayout 包裹进 HorizontalScrollView
+ val scrollView = HorizontalScrollView(context).apply {
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ isHorizontalScrollBarEnabled = true
+ }
+ scrollView.addView(gridLayout)
+
+
+
+
+ // 创建图例(Legend)
+ val legendLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.HORIZONTAL
+ gravity = Gravity.END or Gravity.CENTER_VERTICAL // 靠右对齐
+ setPadding(8, 16, 8, 0)
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ // 左侧“少”标签
+ val labelLow = TextView(context).apply {
+ text = "少"
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+ legendLayout.addView(labelLow)
+
+ // 渐变色块 + 数值
+ val legendLevels = listOf(0, 5, 10, 15, 20)
+ legendLevels.forEach { level ->
+ val colorBox = View(context).apply {
+ setBackgroundColor(getHeatmapColor(level))
+ val size = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ layoutParams = LinearLayout.LayoutParams(size, size).apply {
+ marginEnd = 4
+ }
+ }
+
+ val label = TextView(context).apply {
+// text = "$level"
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+
+ legendLayout.addView(colorBox)
+ legendLayout.addView(label)
+ }
+
+ // 右侧“多”标签
+ val labelHigh = TextView(context).apply {
+ text = "多"
+ textSize = 10f
+ setPadding(8, 0, 0, 0)
+ }
+ legendLayout.addView(labelHigh)
+
+ // 垂直组合 gridLayout + legendLayout
+ val container = LinearLayout(context).apply {
+ orientation = LinearLayout.VERTICAL
+ addView(scrollView)
+ addView(legendLayout)
+ }
+
+ addView(container)
+ }
+ }
+ }
+
private fun getHeatmapColor(count: Int): Int {
return when {
count == 0 -> Color.parseColor("#EBECF1") // 最淡
--
Gitblit v1.9.3