完善柱状图

This commit is contained in:
wangyu4life 2026-01-28 23:47:05 +08:00
parent 36467af122
commit dba4cdd23f
10 changed files with 125 additions and 88 deletions

View File

@ -3,7 +3,6 @@ package com.cheng.blzb.ui.fragment.guide
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.cheng.blzb.bean.AreaEntity import com.cheng.blzb.bean.AreaEntity
import com.cheng.blzb.bean.GuideTotalBidEntity import com.cheng.blzb.bean.GuideTotalBidEntity
import com.cheng.blzb.bean.GuideUpdateEntity
import com.cheng.blzb.bean.HotWordEntity import com.cheng.blzb.bean.HotWordEntity
import com.cheng.blzb.net.ApiFactory import com.cheng.blzb.net.ApiFactory
import com.example.base.extensions.toast import com.example.base.extensions.toast
@ -15,7 +14,6 @@ class GuideViewModel :BaseViewModel(){
val cityLiveData = MutableLiveData<List<AreaEntity>>() val cityLiveData = MutableLiveData<List<AreaEntity>>()
val userCityLiveData = MutableLiveData<AreaEntity>() val userCityLiveData = MutableLiveData<AreaEntity>()
val totalLiveData = MutableLiveData<GuideTotalBidEntity>() val totalLiveData = MutableLiveData<GuideTotalBidEntity>()
val updateLiveData = MutableLiveData<List<GuideUpdateEntity>>()
fun getHotWordList() { fun getHotWordList() {
launchOnUiTryCatch({ launchOnUiTryCatch({
@ -64,16 +62,4 @@ class GuideViewModel :BaseViewModel(){
L.d(it) L.d(it)
}) })
} }
fun getUpdateNum() {
launchOnUiTryCatch({
val response = ApiFactory.apiService.getUpdateNum("8")
if (response.status) {
updateLiveData.postValue(response.data)
} else toast(response.message, true)
}, {
setError(it)
L.d(it)
})
}
} }

View File

@ -7,6 +7,7 @@ import android.os.Build
import android.text.TextUtils import android.text.TextUtils
import android.view.View import android.view.View
import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.TextView
import android.window.OnBackInvokedDispatcher import android.window.OnBackInvokedDispatcher
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.core.animation.addListener import androidx.core.animation.addListener
@ -148,6 +149,33 @@ class GuideVipFragment: BaseFragment<FragmentGuideVipBinding, GuideVipViewModel>
requireActivity().startActivity<MainActivity>() requireActivity().startActivity<MainActivity>()
} }
binding.tvTab1.onClick {
binding.layoutTotalInfo.visible()
binding.layoutChart.gone()
updateTabStyle(binding.tvTab1)
}
binding.tvTab2.onClick {
binding.layoutTotalInfo.gone()
binding.layoutChart.visible()
updateTabStyle(binding.tvTab2)
setChartData()
}
binding.tvTab3.onClick {
binding.layoutTotalInfo.gone()
binding.layoutChart.visible()
updateTabStyle(binding.tvTab3)
setChartData()
}
binding.tvTab4.onClick {
binding.layoutTotalInfo.gone()
binding.layoutChart.visible()
updateTabStyle(binding.tvTab4)
setChartData()
}
binding.tvAliPay.onClick { binding.tvAliPay.onClick {
payType = 1 payType = 1
checkPayType() checkPayType()
@ -211,7 +239,7 @@ class GuideVipFragment: BaseFragment<FragmentGuideVipBinding, GuideVipViewModel>
} }
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged", "SetTextI18n")
override fun initObserve() { override fun initObserve() {
super.initObserve() super.initObserve()
mViewModel.goodsListLiveData.observe(this) { list -> mViewModel.goodsListLiveData.observe(this) { list ->
@ -248,7 +276,6 @@ class GuideVipFragment: BaseFragment<FragmentGuideVipBinding, GuideVipViewModel>
mViewModel.updateLiveData.observe(this) { mViewModel.updateLiveData.observe(this) {
updateInfoList.clear() updateInfoList.clear()
updateInfoList.addAll(it) updateInfoList.addAll(it)
setChartData()
binding.tvChartTitle.text = "月份:${Calendar.getInstance().get(Calendar.MONTH) + 1}月 单位:条" binding.tvChartTitle.text = "月份:${Calendar.getInstance().get(Calendar.MONTH) + 1}月 单位:条"
} }
@ -415,6 +442,25 @@ class GuideVipFragment: BaseFragment<FragmentGuideVipBinding, GuideVipViewModel>
animSet.start() animSet.start()
} }
private fun updateTabStyle(textView: TextView) {
binding.tvTab1.setTextColor(getColor(R.color.color_9bbbdf))
binding.tvTab2.setTextColor(getColor(R.color.color_9bbbdf))
binding.tvTab3.setTextColor(getColor(R.color.color_9bbbdf))
binding.tvTab4.setTextColor(getColor(R.color.color_9bbbdf))
binding.tvTab1.setBackgroundResource(R.mipmap.ic_guide_vip_tab_default)
binding.tvTab2.setBackgroundResource(R.mipmap.ic_guide_vip_tab_default)
binding.tvTab3.setBackgroundResource(R.mipmap.ic_guide_vip_tab_default)
binding.tvTab4.setBackgroundResource(R.mipmap.ic_guide_vip_tab_default)
textView.setTextColor(getColor(R.color.white))
textView.setBackgroundResource(R.mipmap.ic_guide_vip_tab_checked)
val infoRotateAnim = ObjectAnimator.ofFloat(binding.layoutInfo, "rotationX", 90f, -10f, 10f, 0f)
infoRotateAnim.duration = 1000
infoRotateAnim.start()
}
private fun checkPayType() { private fun checkPayType() {
if (payType == 0) { if (payType == 0) {
val start1 = ContextCompat.getDrawable(requireContext(), R.mipmap.ic_wx_pay) val start1 = ContextCompat.getDrawable(requireContext(), R.mipmap.ic_wx_pay)
@ -549,7 +595,7 @@ class GuideVipFragment: BaseFragment<FragmentGuideVipBinding, GuideVipViewModel>
countdownDisposable = RxCountDown.countdown(totalSeconds) countdownDisposable = RxCountDown.countdown(totalSeconds)
.subscribe { .subscribe {
setCountdownTime(it) setCountdownTime(it)
if (it == 0L) { if (it == 0L && !isStateSaved) {
val f = GuideSaleDialog.newInstance() val f = GuideSaleDialog.newInstance()
f.setOnSelectListener { seconds -> f.setOnSelectListener { seconds ->
totalSeconds = seconds totalSeconds = seconds
@ -561,6 +607,7 @@ class GuideVipFragment: BaseFragment<FragmentGuideVipBinding, GuideVipViewModel>
} }
//格式化倒计时 //格式化倒计时
@SuppressLint("DefaultLocale")
private fun setCountdownTime(seconds: Long) { private fun setCountdownTime(seconds: Long) {
val minutes = seconds / 60 val minutes = seconds / 60
val hours = minutes / 60 val hours = minutes / 60

View File

@ -5,9 +5,10 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.animation.addListener import androidx.core.animation.addListener
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder import com.chad.library.adapter.base.viewholder.BaseViewHolder
@ -22,32 +23,54 @@ class BarChartView @JvmOverloads constructor(
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = 0 defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) { ) : FrameLayout(context, attrs, defStyleAttr) {
private val xAxisAdapter by lazy { XAxisAdapter() }
private val yAxisAdapter by lazy { YAxisAdapter() }
private val yAxisRowCount = 6 private val yAxisRowCount = 6
private var maxValue = 0f private var maxYAxisValue = 0f
init { /**
val view = inflate(context, R.layout.layout_bar_chart, null) * 设置X轴数据
addView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) */
private fun setXAxisData(data: List<XAxisValue>, type: Int = 1) {
val rvXAxis = RecyclerView(context)
val adapter = XAxisAdapter(type)
rvXAxis.adapter = adapter
rvXAxis.layoutManager = GridLayoutManager(context, 7)
val xAxisLp = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
xAxisLp.marginStart = DensityUtils.dp2px(50f)
xAxisLp.marginEnd = DensityUtils.dp2px(20f)
rvXAxis.layoutParams = xAxisLp
addView(rvXAxis)
adapter.setList(data)
} }
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { /**
super.onMeasure(widthMeasureSpec, heightMeasureSpec) * 设置Y轴数据
*/
private fun setYAxisData(data: List<YAxisValue>) {
val rvYAxis = RecyclerView(context)
val adapter = YAxisAdapter()
rvYAxis.adapter = adapter
rvYAxis.layoutManager = LinearLayoutManager(context)
val yAxisLp = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
yAxisLp.bottomMargin = DensityUtils.dp2px(15f)
rvYAxis.layoutParams = yAxisLp
addView(rvYAxis)
val rvX = findViewById<RecyclerView>(R.id.rv_x) adapter.setList(data)
rvX.adapter = xAxisAdapter
val rvY = findViewById<RecyclerView>(R.id.rv_y)
rvY.adapter = yAxisAdapter
} }
fun setData(xValueList: List<XAxisValue>) { /**
* 设置数据
*/
fun setData(vararg xValueLists: List<XAxisValue>) {
removeAllViews()
val allValueList = mutableListOf<XAxisValue>()
xValueLists.forEach { allValueList.addAll(it) }
val yValueList = mutableListOf<YAxisValue>() val yValueList = mutableListOf<YAxisValue>()
val rowValue = xValueList.maxBy { it.value }.value / yAxisRowCount val rowValue = allValueList.maxBy { it.value }.value / yAxisRowCount
val value = if (rowValue > 10) { val value = if (rowValue > 10) {
var bigNum = rowValue.toInt().toFloat() var bigNum = rowValue.toInt().toFloat()
val numLength = rowValue.toInt().toString().length val numLength = rowValue.toInt().toString().length
@ -64,40 +87,52 @@ class BarChartView @JvmOverloads constructor(
for (i in 0 .. yAxisRowCount) { for (i in 0 .. yAxisRowCount) {
yValueList.add(0, YAxisValue(i * value)) yValueList.add(0, YAxisValue(i * value))
} }
maxValue = value * yAxisRowCount maxYAxisValue = value * yAxisRowCount
xAxisAdapter.setList(xValueList) setYAxisData(yValueList)
yAxisAdapter.setList(yValueList) xValueLists.forEachIndexed { index, xAxisValues ->
setXAxisData(xAxisValues, index + 1)
}
} }
data class XAxisValue(val value: Float, val date: String) data class XAxisValue(val value: Float, val date: String, var anim: Boolean = true)
data class YAxisValue(val value: Float) data class YAxisValue(val value: Float)
inner class XAxisAdapter : BaseQuickAdapter<XAxisValue, BaseViewHolder>(R.layout.listitem_bar_chart_x) { inner class XAxisAdapter(val type: Int) : BaseQuickAdapter<XAxisValue, BaseViewHolder>(R.layout.listitem_bar_chart_x) {
override fun convert(holder: BaseViewHolder, item: XAxisValue) { override fun convert(holder: BaseViewHolder, item: XAxisValue) {
holder.setText(R.id.tv_value, "${DecimalFormat("0.#").format(item.value)}") holder.setText(R.id.tv_value, DecimalFormat("0.#").format(item.value))
holder.setText(R.id.tv_date, item.date) holder.setText(R.id.tv_date, item.date)
if (type == 1) {
val lp = holder.getView<ImageView>(R.id.iv_bar).layoutParams as ConstraintLayout.LayoutParams holder.setImageResource(R.id.iv_bar, R.mipmap.ic_bar_chart1)
lp.height = (item.value / maxValue * recyclerView.measuredHeight * yAxisRowCount / (yAxisRowCount + 1)).toInt() - DensityUtils.dp2px(6f) holder.setImageResource(R.id.iv_bar_top, R.mipmap.ic_bar_chart_top1)
(holder.getView<ImageView>(R.id.iv_bar)).layoutParams = lp } else {
// startAnim(holder.getView(R.id.iv_bar), item) holder.setImageResource(R.id.iv_bar, R.mipmap.ic_bar_chart2)
holder.setImageResource(R.id.iv_bar_top, R.mipmap.ic_bar_chart_top2)
} }
private fun startAnim(barView: View, item: XAxisValue) { if (item.anim) {
startAnimation(holder.getView(R.id.iv_bar), item)
item.anim = false
} else {
holder.setVisible(R.id.iv_bar, true)
}
}
private fun startAnimation(barView: View, item: XAxisValue) {
val itemHeight = (item.value / maxYAxisValue * recyclerView.measuredHeight * yAxisRowCount / (yAxisRowCount + 1)).toInt() - DensityUtils.dp2px(10f)
val valueAnim = ValueAnimator.ofFloat(0f, 1f) val valueAnim = ValueAnimator.ofFloat(0f, 1f)
valueAnim.addUpdateListener { animator -> valueAnim.addUpdateListener { animator ->
val value = animator.animatedValue as Float
val itemHeight = (item.value / maxValue * recyclerView.measuredHeight * yAxisRowCount / (yAxisRowCount + 1)).toInt() - DensityUtils.dp2px(6f)
val lp = barView.layoutParams as ConstraintLayout.LayoutParams val lp = barView.layoutParams as ConstraintLayout.LayoutParams
lp.height = (value * itemHeight).toInt() val value = animator.animatedValue as Float
lp.height = (value * itemHeight).coerceAtLeast(DensityUtils.dp2px(6f).toFloat()).toInt()
barView.layoutParams = lp barView.layoutParams = lp
} }
valueAnim.addListener(onStart = { valueAnim.addListener(onStart = {
barView.visible() barView.visible()
}) })
valueAnim.duration = 1000 valueAnim.duration = 2000
valueAnim.startDelay = 1000
valueAnim.start() valueAnim.start()
} }
} }
@ -109,7 +144,7 @@ class BarChartView @JvmOverloads constructor(
lp.height = recyclerView.measuredHeight / (yAxisRowCount + 1) lp.height = recyclerView.measuredHeight / (yAxisRowCount + 1)
holder.itemView.layoutParams = lp holder.itemView.layoutParams = lp
holder.setText(R.id.tv_value, "${DecimalFormat("0.#").format(item.value)}") holder.setText(R.id.tv_value, DecimalFormat("0.#").format(item.value))
} }
} }
} }

View File

@ -163,7 +163,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@mipmap/ic_guide_vip_info_bg" android:background="@mipmap/ic_guide_vip_info_bg"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
@ -351,7 +350,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@mipmap/ic_guide_vip_info_bg" android:background="@mipmap/ic_guide_vip_info_bg"
android:visibility="visible" android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<TextView <TextView

View File

@ -1,28 +0,0 @@
<?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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_y"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/dp_15"
android:orientation="vertical"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/listitem_bar_chart_y" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_x"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dp_50"
android:layout_marginEnd="@dimen/dp_20"
android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="7"
tools:listitem="@layout/listitem_bar_chart_x" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,8 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
xmlns:tools="http://schemas.android.com/tools">
<TextView <TextView
android:id="@+id/tv_value" android:id="@+id/tv_value"
@ -18,10 +17,11 @@
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_bar_top"
android:layout_width="@dimen/dp_20" android:layout_width="@dimen/dp_20"
android:layout_height="@dimen/dp_6" android:layout_height="@dimen/dp_6"
android:layout_marginBottom="-3dp" android:layout_marginBottom="-3dp"
android:src="@mipmap/ic_bar_chart_top" android:src="@mipmap/ic_bar_chart_top1"
app:layout_constraintBottom_toTopOf="@id/iv_bar" app:layout_constraintBottom_toTopOf="@id/iv_bar"
app:layout_constraintEnd_toEndOf="@id/iv_bar" app:layout_constraintEnd_toEndOf="@id/iv_bar"
app:layout_constraintStart_toStartOf="@id/iv_bar" /> app:layout_constraintStart_toStartOf="@id/iv_bar" />
@ -29,12 +29,10 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_bar" android:id="@+id/iv_bar"
android:layout_width="@dimen/dp_20" android:layout_width="@dimen/dp_20"
android:layout_height="wrap_content" android:layout_height="@dimen/dp_6"
android:layout_marginBottom="@dimen/dp_5" android:layout_marginBottom="@dimen/dp_5"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@mipmap/ic_bar_chart" android:src="@mipmap/ic_bar_chart1"
android:visibility="visible"
tools:visibility="visible"
app:layout_constraintBottom_toTopOf="@id/tv_date" app:layout_constraintBottom_toTopOf="@id/tv_date"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B