From 8dcf3b77c782d55649a75bce2b8a23702041a977 Mon Sep 17 00:00:00 2001 From: lijia Date: Wed, 7 Feb 2024 17:12:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BD=A6=E9=98=9F=E7=AE=A1=E7=90=86=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dahe/gldriver/adapter/DriversAdapter.kt | 31 ++ .../dahe/gldriver/adapter/PagersAdapter.kt | 31 ++ .../com/dahe/gldriver/ui/mine/MineFragment.kt | 2 +- .../ui/mine/activity/CarTeamActivity.kt | 122 +++++++ .../ui/mine/activity/WalletActivity.kt | 2 + .../ui/mine/fragment/CarsManFragment.kt | 58 ++++ .../ui/mine/fragment/DriversManFragment.kt | 59 ++++ app/src/main/res/layout/activity_car_team.xml | 71 ++-- app/src/main/res/layout/activity_wallet.xml | 20 +- app/src/main/res/layout/fragment_waybill.xml | 2 +- app/src/main/res/layout/item_driver.xml | 57 ++++ .../dahe/mylibrary/weight/CircleBarView.java | 323 ++++++++++++++++++ .../dahe/mylibrary/weight/CircleBarView2.java | 259 ++++++++++++++ mylibrary/src/main/res/values/colors.xml | 5 + mylibrary/src/main/res/values/styles.xml | 24 ++ 15 files changed, 1005 insertions(+), 61 deletions(-) create mode 100644 app/src/main/java/com/dahe/gldriver/adapter/DriversAdapter.kt create mode 100644 app/src/main/java/com/dahe/gldriver/adapter/PagersAdapter.kt create mode 100644 app/src/main/java/com/dahe/gldriver/ui/mine/fragment/CarsManFragment.kt create mode 100644 app/src/main/java/com/dahe/gldriver/ui/mine/fragment/DriversManFragment.kt create mode 100644 app/src/main/res/layout/item_driver.xml create mode 100644 mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView.java create mode 100644 mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView2.java diff --git a/app/src/main/java/com/dahe/gldriver/adapter/DriversAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/DriversAdapter.kt new file mode 100644 index 0000000..ad8adaa --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/DriversAdapter.kt @@ -0,0 +1,31 @@ +package com.dahe.gldriver.adapter + +import android.content.Context +import android.view.ViewGroup +import android.widget.Button +import com.chad.library.adapter4.BaseQuickAdapter +import com.chad.library.adapter4.viewholder.QuickViewHolder +import com.dahe.gldriver.R +import com.dahe.glex.bean.WayBillBean + +/** + * @ClassName WaybillAdapter + * @Author 用户 + * @Date 2024/1/23 16:27 + * @Description TODO + */ +class DriversAdapter : + BaseQuickAdapter() { + override fun onBindViewHolder(holder: QuickViewHolder, position: Int, item: WayBillBean?) { + + } + + override fun onCreateViewHolder( + context: Context, + parent: ViewGroup, + viewType: Int + ): QuickViewHolder { + // 返回一个 ViewHolder + return QuickViewHolder(R.layout.item_driver, parent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/adapter/PagersAdapter.kt b/app/src/main/java/com/dahe/gldriver/adapter/PagersAdapter.kt new file mode 100644 index 0000000..a10fef1 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/adapter/PagersAdapter.kt @@ -0,0 +1,31 @@ +package com.dahe.gldriver.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.adapter.FragmentStateAdapter + + +/** + * @ClassName PagersAdapter + * @Author john + * @Date 2024/2/7 10:26 + * @Description TODO + */ +class PagersAdapter(fragmentActivity: FragmentActivity,list:MutableList) : FragmentStateAdapter(fragmentActivity) { + private var fragmentList : MutableList =ArrayList() + init { + this.fragmentList = list + } + + override fun getItemCount(): Int { + return fragmentList.size + } + + override fun createFragment(position: Int): Fragment { + return fragmentList[position] + } + + fun addFragment(fragment: Fragment){ + fragmentList.add(fragment) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt index db2859e..78dff3b 100644 --- a/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt +++ b/app/src/main/java/com/dahe/gldriver/ui/mine/MineFragment.kt @@ -95,7 +95,7 @@ class MineFragment : BaseFragment(), View.OnClickListener { private fun goTools(pos: Int) { when (pos) { 0 -> { - ActivityUtils.startActivity(mContext, RulesActivity::class.java) + ActivityUtils.startActivity(mContext, CarTeamActivity::class.java) } 1 -> { diff --git a/app/src/main/java/com/dahe/gldriver/ui/mine/activity/CarTeamActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/mine/activity/CarTeamActivity.kt index 946a869..98f7fe6 100644 --- a/app/src/main/java/com/dahe/gldriver/ui/mine/activity/CarTeamActivity.kt +++ b/app/src/main/java/com/dahe/gldriver/ui/mine/activity/CarTeamActivity.kt @@ -1,8 +1,25 @@ package com.dahe.gldriver.ui.mine.activity +import android.content.Context +import android.graphics.Color import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.dahe.gldriver.adapter.PagersAdapter import com.dahe.gldriver.databinding.ActivityCarTeamBinding +import com.dahe.gldriver.ui.mine.fragment.CarsManFragment +import com.dahe.gldriver.ui.mine.fragment.DriversManFragment +import com.dahe.gldriver.ui.waybill.fragment.AllWaybillFragment import com.dahe.mylibrary.base.BaseActivity +import net.lucode.hackware.magicindicator.FragmentContainerHelper +import net.lucode.hackware.magicindicator.buildins.UIUtil +import net.lucode.hackware.magicindicator.buildins.commonnavigator.CommonNavigator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView +import net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.ColorTransitionPagerTitleView + /** * @ClassName CarTeamActivity @@ -11,11 +28,116 @@ import com.dahe.mylibrary.base.BaseActivity * @Description 车队管理 */ class CarTeamActivity : BaseActivity() { + + private val mFragmentContainerHelper = FragmentContainerHelper() + var mFragments = mutableListOf( + DriversManFragment(), + CarsManFragment(), + AllWaybillFragment() + ) + val titles = mutableListOf( + "司机管理", + "车辆管理", + "车队订单" + ) + + override fun initView(savedInstanceState: Bundle?) { setStatusHeightParams(binding.rlTop) setTitleBar("车队管理",true,true) + + var pagerAdapter = PagersAdapter(this,mFragments) +// pagerAdapter.addFragment(AllWaybillFragment()) +// pagerAdapter.addFragment(AllWaybillFragment()) +// pagerAdapter.addFragment(AllWaybillFragment()) + + + binding.circleBarView.setProgress(30f,1000) + + binding.circleBarView2.run { + text = "高风险" + valueText = "0" + unitText= "分" + progress = 60 + } + + mFragmentContainerHelper.handlePageSelected(0,true) + + binding.viewPager.adapter = pagerAdapter + binding.viewPager.currentItem = 0 + binding.viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + mFragmentContainerHelper.handlePageSelected(position,true) + } + }); + + var commonNavigator = CommonNavigator(mContext) + commonNavigator.run { + isAdjustMode = true + adapter = object : CommonNavigatorAdapter() { + override fun getCount(): Int { + return titles.size + } + + override fun getTitleView(context: Context?, index: Int): IPagerTitleView { + val colorTransitionPagerTitleView = ColorTransitionPagerTitleView(context) + colorTransitionPagerTitleView.normalColor = Color.BLACK + colorTransitionPagerTitleView.selectedColor = Color.RED + colorTransitionPagerTitleView.text = titles[index] + colorTransitionPagerTitleView.setOnClickListener { + mFragmentContainerHelper.handlePageSelected(index) + switchPages(index) + } + return colorTransitionPagerTitleView + } + + override fun getIndicator(context: Context?): IPagerIndicator { + val indicator = LinePagerIndicator(context) + indicator.mode = LinePagerIndicator.MODE_WRAP_CONTENT + indicator.yOffset = + UIUtil.dip2px(context, 3.0).toFloat() + indicator.setColors(Color.RED) + return indicator + } + + } + } + + binding.magicIndicator.navigator = commonNavigator + mFragmentContainerHelper.attachMagicIndicator(binding.magicIndicator) } override fun initDate() { } + + private fun switchPages(index: Int){ + binding.viewPager.currentItem = index + } + +// private fun switchPages(index: Int) { +// val fragmentManager = supportFragmentManager +// val fragmentTransaction = fragmentManager.beginTransaction() +// var fragment: Fragment +// var i = 0 +// val j: Int = mFragments.size +// while (i < j) { +// if (i == index) { +// i++ +// continue +// } +// fragment = mFragments[i] +// if (fragment.isAdded) { +// fragmentTransaction.hide(fragment) +// } +// i++ +// } +// fragment = mFragments[index] +// if (fragment.isAdded) { +// fragmentTransaction.show(fragment) +// } else { +// fragmentTransaction.add(R.id.fragmentContainer, fragment) +// } +// fragmentTransaction.commitAllowingStateLoss() +// } } \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/mine/activity/WalletActivity.kt b/app/src/main/java/com/dahe/gldriver/ui/mine/activity/WalletActivity.kt index 07939e0..bf5b4ba 100644 --- a/app/src/main/java/com/dahe/gldriver/ui/mine/activity/WalletActivity.kt +++ b/app/src/main/java/com/dahe/gldriver/ui/mine/activity/WalletActivity.kt @@ -21,6 +21,8 @@ import com.dahe.mylibrary.utils.ConvertUtils */ class WalletActivity : BaseActivity() { override fun initView(savedInstanceState: Bundle?) { + setStatusHeightParams(binding.rlTop) + setTitleBar("钱包",true,true) } override fun initDate() { diff --git a/app/src/main/java/com/dahe/gldriver/ui/mine/fragment/CarsManFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/mine/fragment/CarsManFragment.kt new file mode 100644 index 0000000..91474ab --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/mine/fragment/CarsManFragment.kt @@ -0,0 +1,58 @@ +package com.dahe.gldriver.ui.mine.fragment + +import android.graphics.Color +import android.os.Bundle +import android.widget.LinearLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.LayoutManager +import com.dahe.gldriver.R +import com.dahe.gldriver.adapter.CarsAdapter +import com.dahe.gldriver.adapter.WaybillAdapter +import com.dahe.gldriver.databinding.ActivityCarsManBinding +import com.dahe.gldriver.databinding.FragmentWaybillListBinding +import com.dahe.glex.bean.WayBillBean +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.base.BaseFragment +import com.dahe.mylibrary.recycleviewswipe.RecycleViewDivider +import com.dahe.mylibrary.utils.ConvertUtils + +/** + * @ClassName CarsManActivity + * @Author john + * @Date 2024/2/1 08:59 + * @Description 车辆管理 + */ +class CarsManFragment : BaseFragment() { + + override fun onFragmentVisibleChange(isVisible: Boolean) { + } + + override fun onFragmentFirstVisible() { + var datas = mutableListOf( + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean() + ) + + var adapter = binding.recyclerView.run { + layoutManager = LinearLayoutManager(mContext, RecyclerView.VERTICAL, false) + addItemDecoration( + RecycleViewDivider( + LinearLayout.VERTICAL, + ConvertUtils.dp2px(16.0f), + Color.TRANSPARENT + ) + ) + adapter = CarsAdapter() + adapter as CarsAdapter + } + + adapter.submitList(datas) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dahe/gldriver/ui/mine/fragment/DriversManFragment.kt b/app/src/main/java/com/dahe/gldriver/ui/mine/fragment/DriversManFragment.kt new file mode 100644 index 0000000..96dc063 --- /dev/null +++ b/app/src/main/java/com/dahe/gldriver/ui/mine/fragment/DriversManFragment.kt @@ -0,0 +1,59 @@ +package com.dahe.gldriver.ui.mine.fragment + +import android.graphics.Color +import android.os.Bundle +import android.widget.LinearLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.LayoutManager +import com.dahe.gldriver.R +import com.dahe.gldriver.adapter.CarsAdapter +import com.dahe.gldriver.adapter.DriversAdapter +import com.dahe.gldriver.adapter.WaybillAdapter +import com.dahe.gldriver.databinding.ActivityCarsManBinding +import com.dahe.gldriver.databinding.FragmentWaybillListBinding +import com.dahe.glex.bean.WayBillBean +import com.dahe.mylibrary.base.BaseActivity +import com.dahe.mylibrary.base.BaseFragment +import com.dahe.mylibrary.recycleviewswipe.RecycleViewDivider +import com.dahe.mylibrary.utils.ConvertUtils + +/** + * @ClassName CarsManActivity + * @Author john + * @Date 2024/2/1 08:59 + * @Description 车辆管理 + */ +class DriversManFragment : BaseFragment() { + + override fun onFragmentVisibleChange(isVisible: Boolean) { + } + + override fun onFragmentFirstVisible() { + var datas = mutableListOf( + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean(), + WayBillBean() + ) + + var adapter = binding.recyclerView.run { + layoutManager = LinearLayoutManager(mContext, RecyclerView.VERTICAL, false) + addItemDecoration( + RecycleViewDivider( + LinearLayout.VERTICAL, + ConvertUtils.dp2px(16.0f), + Color.TRANSPARENT + ) + ) + adapter = DriversAdapter() + adapter as DriversAdapter + } + + adapter.submitList(datas) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_car_team.xml b/app/src/main/res/layout/activity_car_team.xml index 179d5be..09b7c0d 100644 --- a/app/src/main/res/layout/activity_car_team.xml +++ b/app/src/main/res/layout/activity_car_team.xml @@ -15,11 +15,27 @@ + + + + + - + /> - - - - - - - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_wallet.xml b/app/src/main/res/layout/activity_wallet.xml index 9c03c32..b03a906 100644 --- a/app/src/main/res/layout/activity_wallet.xml +++ b/app/src/main/res/layout/activity_wallet.xml @@ -4,27 +4,13 @@ android:layout_height="match_parent"> + android:background="@drawable/wallet_bg"> - + - - //搜索 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView.java new file mode 100644 index 0000000..302bb36 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView.java @@ -0,0 +1,323 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.SweepGradient; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.widget.TextView; + +import com.dahe.mylibrary.R; + +/** + * @ClassName CircleBarView + * @Author john + * @Date 2024/2/7 16:08 + * @Description TODO + */ +public class CircleBarView extends View { + private Paint rPaint;//绘制矩形的画笔 + private Paint progressPaint;//绘制圆弧的画笔 + private Paint anchorPaint, anchorBgPaint;//锚点 + private float anchorRadius, anchorBgRadius; + private int anchorColor, anchorBgColor; + private CircleBarAnim anim; + private Paint bgPaint;//绘制背景圆弧的画笔 + private float progress;//可以更新的进度条数值 + private float maxProgress;//进度条最大值 + private float progressSweepAngle;//进度条圆弧扫过的角度 + private int startAngle;//背景圆弧的起始角度 + private float sweepAngle;//背景圆弧扫过的角度 + private RectF mRectF;//绘制圆弧的矩形区域 + private float barWidth;//圆弧进度条宽度 + private int defaultSize;//自定义View默认的宽高 + private int[] progressColors;//进度条圆弧颜色 + private int bgColor;//背景圆弧颜色 + private SweepGradient sweepGradient;//进度条颜色使用渐变色 + private LinearGradient linearGradient; + private float circleWidth, circleHeight; + private float xDiff; + + public CircleBarView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleBarView); + int color1 = typedArray.getColor(R.styleable.CircleBarView_progress_color1, Color.RED); + int color2 = typedArray.getColor(R.styleable.CircleBarView_progress_color2, color1); + int color3 = typedArray.getColor(R.styleable.CircleBarView_progress_color3, color2);//写法巧妙 + progressColors = new int[]{color1, color1, color2, color3};//必须得4个, + bgColor = typedArray.getColor(R.styleable.CircleBarView_bg_color, Color.GRAY);//默认为灰色 + circleWidth = typedArray.getDimension(R.styleable.CircleBarView_circle_width, dip2px(context, 200));//默认为0 + circleHeight = typedArray.getDimension(R.styleable.CircleBarView_circle_height, dip2px(context, 80));//默认为360 + barWidth = typedArray.getDimension(R.styleable.CircleBarView_bar_width, dip2px(context, 10));//默认为10dp + anchorRadius = typedArray.getDimension(R.styleable.CircleBarView_anchor_radius, dip2px(context, 5)); + anchorBgRadius = typedArray.getDimension(R.styleable.CircleBarView_anchor_bg_radius, dip2px(context, 8.5f)); + anchorColor = typedArray.getColor(R.styleable.CircleBarView_anchor_color, Color.RED); + anchorBgColor = typedArray.getColor(R.styleable.CircleBarView_anchor_bg_color, Color.GREEN); + maxProgress = typedArray.getInt(R.styleable.CircleBarView_progress_max, 100); + typedArray.recycle();//typedArray用完之后需要回收,防止内存泄漏 + + rPaint = new Paint(); + rPaint.setStyle(Paint.Style.STROKE);//只描边,不填充 + rPaint.setColor(Color.RED); + + progressPaint = new Paint(); + progressPaint.setStyle(Paint.Style.STROKE);//只描边,不填充 + + progressPaint.setStrokeWidth(barWidth); + progressPaint.setAntiAlias(true);//设置抗锯齿 + progressPaint.setStrokeCap(Paint.Cap.ROUND); + + //锚点 + anchorPaint = new Paint(); + anchorPaint.setAntiAlias(true);//设置抗锯齿 + anchorPaint.setColor(anchorColor); + //锚点背景 + anchorBgPaint = new Paint(); + anchorBgPaint.setAntiAlias(true);//设置抗锯齿 + + int a = Color.alpha(anchorBgColor); + int r = Color.red(anchorBgColor); + int g = Color.green(anchorBgColor); + int b = Color.blue(anchorBgColor); +// LogSuperUtil.i("circle_bar", "a=" + a + ",r=" + r + ",g=" + g + ",b=" + b); + anchorBgPaint.setColor(Color.rgb(r, g, b)); + anchorBgPaint.setAlpha(a); + /*raw + anchorBgPaint.setColor(anchorBgColor); + anchorBgPaint.setAlpha(185);*/ + + anim = new CircleBarAnim(); + bgPaint = new Paint(); + bgPaint.setStyle(Paint.Style.STROKE); + bgPaint.setColor(bgColor); + bgPaint.setStrokeWidth(barWidth); + bgPaint.setAntiAlias(true); + bgPaint.setStrokeCap(Paint.Cap.ROUND); + mRectF = new RectF(); + + // + defaultSize = dip2px(context, 200); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + //进度条的总轮廓 + canvas.drawArc(mRectF, startAngle, sweepAngle, false, bgPaint); + float outCircleRadius = mRectF.width() / 2;//带宽度的进度条的中线半径 + + if (sweepGradient == null) { + float centerX = (mRectF.left + mRectF.right) / 2; + float centerY = (mRectF.top + mRectF.bottom) / 2; + // + int rotateDiff = 30;//为了解决圆弧开头出的圆角颜色不正常的问题,30度够用了吧 + int rotateDegree = startAngle - rotateDiff; + float sweepEndPosition = (rotateDiff + sweepAngle * progress / maxProgress * 1.0f) / 360; +// LogSuperUtil.i("circle_bar", "startAngle=" + startAngle + ",sweepEndPosition=" + sweepEndPosition); + + float[] positions = {0, rotateDiff * 1.0f / 360, sweepEndPosition, 1}; + sweepGradient = new SweepGradient(centerX, centerY, progressColors, positions); + Matrix rotateMatrix = new Matrix(); + //设置渐变色 + rotateMatrix.setRotate(rotateDegree, centerX, centerY);//180表示从左侧开始往上渐变 + sweepGradient.setLocalMatrix(rotateMatrix);//sweepGradient默认是从0度方向开始渐变的,所以要逆转一下。 + progressPaint.setShader(sweepGradient); + } + /* + if(linearGradient==null) { + linearGradient = new LinearGradient(0, 0, outCircleRadius*2, 0, progressColors, + null, LinearGradient.TileMode.CLAMP); + progressPaint.setShader(linearGradient); + }*/ + //进度条 + canvas.drawArc(mRectF, startAngle, progressSweepAngle, false, progressPaint); + float anchorAngle = progressSweepAngle + (startAngle - 180); + + float anchorCoordRedius = outCircleRadius - barWidth / 2; + double cosValue = Math.cos(Math.toRadians(anchorAngle)); + double sinValue = Math.sin(Math.toRadians(anchorAngle)); + + float diffByAnchor = anchorBgRadius - barWidth / 2;//x和y的偏移正好都是这个 + //float cx=(float)(outCircleRadius-cosValue*anchorCoordRedius+diffByAnchor); + float cx = (float) (outCircleRadius - cosValue * outCircleRadius + anchorBgRadius); + //float cy=(float)(outCircleRadius-sinValue*anchorCoordRedius+diffByAnchor); + float cy = (float) (outCircleRadius - sinValue * outCircleRadius + anchorBgRadius); + canvas.drawCircle(cx - xDiff, cy, anchorRadius, anchorPaint);//锚点小圆 + canvas.drawCircle(cx - xDiff, cy, anchorBgRadius, anchorBgPaint);//锚点背景大圆 + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + //int height=measureSize(defaultSize,heightMeasureSpec); + //int width=measureSize(defaultSize,widthMeasureSpec); + //startAngle是计算出来的,因为弦的这种,没法通过观察直接得出圆弧的起始角度 + //通过数学计算得知x + //x是圆心(圆弧所在的圆的圆心)到弦(也就是圆弧的底部)的垂直距离 + float x = (circleWidth * circleWidth - 4 * circleHeight * circleHeight) / (8 * circleHeight); + //画圆弧用到的圆的半径 + float r = x + circleHeight; + //int r=(int)(circleWidth/2/Math.cos(Math.toRadians(startAngle-180))); + //弦长/2/半径=cos(startAngle-180) + //(startAngle-180) + double asin = Math.asin(circleWidth / 2 / r); + //LogSuperUtil.i("circle_bar","asin="+asin); + int a = (int) Math.toDegrees(asin); + //LogSuperUtil.i("circle_bar","a="+a); + startAngle = 180 + (90 - a); + sweepAngle = 2 * a; + //int min=Math.max(width,height);//获取View最短边的长度 + int width = (int) (Math.sqrt(Math.pow(r + anchorBgRadius, 2) - Math.pow(x, 2)) * 2 + 0.5f + anchorBgRadius);//圆弧的宽度 + width = (int) (2 * (circleWidth / 2 + anchorBgRadius) + 0.5f); + int height = (int) (circleHeight + anchorBgRadius + 0.5f + anchorBgRadius); + //height=width; + xDiff = r - circleWidth / 2;//画布是从最左边开始画圆且显示的,不偏移的话,显示的效果不对。 +// LogSuperUtil.i("circle_bar", "xDiff=" + xDiff); + setMeasuredDimension(width, height); + if (Math.min(width, height) >= barWidth * 2) {//这里简单限制了圆弧的最大宽度 + //1.mRectF决定着圆画在哪个框框里面 + //2.mRectF在当前View中,但不是完全占据当前View + //3.弧度的粗细画的时候是均分到圆半径线的两侧的 + //4.之所以矩形设置的四个点有偏移,是因为有弧度宽度。 + //因为锚点也有宽度,点再次做调整. + //mRectF.set(barWidth/2,barWidth/2,min-barWidth/2,min-barWidth/2); + float diffByAnchor = anchorBgRadius - barWidth / 2;//受锚点影响需要修正的偏移 + //是整个圆的矩形,不是弧形区域所在的矩形 + mRectF.set(barWidth / 2 + diffByAnchor - xDiff, barWidth / 2 + diffByAnchor, barWidth / 2 + diffByAnchor + 2 * r - xDiff, barWidth / 2 + diffByAnchor + 2 * r); + } + } + + private int measureSize(int defaultSize, int measureSpec) { + int result = defaultSize; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + if (specMode == MeasureSpec.EXACTLY) { +// LogSuperUtil.i("circle_bar", "=EXACTLY"); + result = specSize; + } else if (specMode == MeasureSpec.AT_MOST) { +// LogSuperUtil.i("circle_bar", "=AT_MOST"); + result = Math.min(result, specSize); + } else { +// LogSuperUtil.i("circle_bar", "=defaultSize"); + } + return result; + } + + private TextView textView; + private OnAnimationListener onAnimationListener; + + public class CircleBarAnim extends Animation { + public CircleBarAnim() { + + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + super.applyTransformation(interpolatedTime, t); + progressSweepAngle = interpolatedTime * sweepAngle * progress / maxProgress;//这里计算进度条的比例 + postInvalidate(); + if (textView != null && onAnimationListener != null) { + textView.setText(onAnimationListener.howToChangeText(interpolatedTime, progress, maxProgress)); + } + } + } + + /** + * 设置显示文字的TextView + * + * @param textView + */ + public void setTextView(TextView textView) { + this.textView = textView; + } + /* + * circleBarView.setOnAnimationListener(new CircleBarView.OnAnimationListener() { + @Override + public String howToChangeText(float interpolatedTime, float progressNum, float maxNum) { + DecimalFormat decimalFormat=new DecimalFormat("0.00"); + String s = decimalFormat.format(interpolatedTime * progressNum / maxNum * 100) + "%"; + return s; + } +});*/ + + + public interface OnAnimationListener { + /** + * 如何处理要显示的文字内容 + * + * @param interpolatedTime 从0渐变成1,到1时结束动画 + * @param progressNum 进度条数值 + * @param maxNum 进度条最大值 + * @return + */ + String howToChangeText(float interpolatedTime, float progressNum, float maxNum); + } + + //写个方法给外部调用,用来设置动画时间 + public void setProgress(float progress, int time) { + anim.setDuration(time); + this.startAnimation(anim); + this.progress = progress; + } + + public static int dip2px(Context context, float dpValue) { + float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + public static int px2dip(Context context, float pxValue) { + float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * //extraDistance比较小时,TextView离圆弧很近,是正常,因为TextView是从其自身的左上角开始渲染。 + * + * @param sweepAnglePercent + * @param extraDistance + * @return + */ + public float getAngleX(float sweepAnglePercent, int extraDistance) { + float outCircleRadius = mRectF.width() / 2 + barWidth / 2;//带宽度的进度条的外圆半径 + float diffByAnchor = anchorBgRadius - barWidth / 2;//x和y的偏移正好都是这个 + float x = (float) (outCircleRadius + diffByAnchor - Math.cos(Math.toRadians(startAngle - 180 + sweepAnglePercent * sweepAngle)) * (outCircleRadius + dip2px(getContext(), extraDistance)) - xDiff); + return x; + } + + private static final String TAG = "circle_bar"; + + /** + * 在当前View中的y坐标 + * (注意,TextView渲染的时候,这个坐标是作为TextView控件的左上角进行渲染。 + * 所以,extraDistance小的话,显示的结果TextView可能还在当前View的内部呢,但TextView的左上角是在圆外部的。 + * + * @param sweepAnglePercent + * @param extraDistance 从外圆算的往外扩展的距离,不是从锚点背景边缘往外扩展。 + * @return + */ + public float getAngleY(float sweepAnglePercent, int extraDistance) { + float outCircleRadius = mRectF.width() / 2 + barWidth / 2;//带宽度的进度条的外圆半径 + float diffByAnchor = anchorBgRadius - barWidth / 2;//x和y的偏移正好都是这个 + float coordA = startAngle - 180 + sweepAnglePercent * sweepAngle; +// LogSuperUtil.i("circle_bar", "coordA=" + coordA); + float coordY = (float) Math.sin(Math.toRadians(coordA)) * (outCircleRadius + dip2px(getContext(), extraDistance)); +// LogSuperUtil.i("circle_bar", "coordY=" + coordY); + float tempR = outCircleRadius + diffByAnchor; +// LogSuperUtil.i("circle_bar", "tempR=" + tempR + ",=" + circleWidth);//CircleWidth是圆弧宽度 +// LogSuperUtil.i("circle_bar", "mRectF.width()/2=" + mRectF.width() / 2); + float y = (float) (tempR - coordY); + return y; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView2.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView2.java new file mode 100644 index 0000000..ec1da53 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/CircleBarView2.java @@ -0,0 +1,259 @@ +package com.dahe.mylibrary.weight; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import com.dahe.mylibrary.R; + +/** + * @ClassName CircleBarView2 + * @Author john + * @Date 2024/2/7 16:28 + * @Description TODO + */ +public class CircleBarView2 extends View { + + private Paint outPaint, innerPaint; + + private Paint mTextPaint, mValueTextPaint, mUnitTextPaint; + + private final RectF oval = new RectF(); + + //最大进度 + private int max = 100; + //当前进度 + private int progress = 0; + //文本内容 + private String text = ""; + //数值内容 + private String valueText = ""; + //单位内容 + private String unitText = ""; + // 圆弧颜色 + private int roundColor = getContext().getColor(R.color.color_f25); + // 设置数值颜色 + private int valueColor = getContext().getColor(R.color.color_f25); + //用于动画 + private float nowPro = 0; + private ValueAnimator animator; + // 文字间距 + private int textMargin; + // 圆弧宽度、半径和数值、小间距 + private int roundWidth, radius, smallMargin; + // view的高度 + private int height; + // 中心点 + private final Point centerPoint = new Point(); + // 测量文字的范围 + private final Rect textRect = new Rect(); + + public CircleBarView2(Context context) { + this(context, null); + } + + public CircleBarView2(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleBarView2(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context); + } + + public int getMax() { + return max; + } + + public void setMax(int max) { + this.max = max; + } + + public int getProgress() { + return progress; + } + + public void setProgress(int progress) { + if (this.progress == progress) { + return; + } + if (animator != null && animator.isRunning()) { + animator.cancel(); + } + animator = ValueAnimator.ofFloat(nowPro, progress); + animator.setDuration(1000); + animator.setInterpolator(new DecelerateInterpolator()); + animator.addUpdateListener(animation -> { + nowPro = (float) animation.getAnimatedValue(); + CircleBarView2.this.progress = (int) nowPro; + valueText = String.valueOf(CircleBarView2.this.progress); + invalidate(); + }); + animator.start(); + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getValueText() { + return valueText; + } + + public void setValueText(String valueText) { + this.valueText = valueText; + } + + public String getUnitText() { + return unitText; + } + + public void setUnitText(String unitText) { + this.unitText = unitText; + } + + public void setRoundColor(int roundColor) { + this.roundColor = roundColor; + + invalidate(); + } + + public void setValueColor(int valueColor) { + this.valueColor = valueColor; + invalidate(); + } + + private void initAttrs(Context context) { + // 文字间距 + textMargin = dp2px(context, 5); + // 圆弧宽度 + roundWidth = dp2px(context, 5); + // 半径 + radius = dp2px(context, 72); + height = radius; + // 小间距 + smallMargin = roundWidth / 2; + + outPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outPaint.setColor(context.getColor(R.color.color_f6)); + outPaint.setStyle(Paint.Style.STROKE); + outPaint.setStrokeCap(Paint.Cap.ROUND); + outPaint.setStrokeWidth(roundWidth); + + innerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + innerPaint.setColor(context.getColor(R.color.color_f15)); + innerPaint.setStyle(Paint.Style.STROKE); + innerPaint.setStrokeCap(Paint.Cap.ROUND); + innerPaint.setStrokeWidth(roundWidth); + + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setColor(context.getColor(R.color.color_ff3)); + mTextPaint.setTextSize(sp2px(getContext(), 24)); + + mValueTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mValueTextPaint.setColor(valueColor); + mValueTextPaint.setTextSize(sp2px(getContext(), 24)); + + mUnitTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mUnitTextPaint.setColor(context.getColor(R.color.color_ff3)); + mUnitTextPaint.setTextSize(sp2px(getContext(), 12)); + + //动画 + animator = ValueAnimator.ofFloat(0, progress); + animator.setDuration(1000); + animator.setInterpolator(new DecelerateInterpolator()); + animator.addUpdateListener(animation -> { + nowPro = (float) animation.getAnimatedValue(); + postInvalidate(); + }); + animator.start(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); + int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); + int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); + if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { + setMeasuredDimension(widthSpecSize, (int) height); + } else if (widthSpecMode == MeasureSpec.AT_MOST) { + setMeasuredDimension(widthSpecSize, heightSpecSize); + height = heightSpecSize; + } else if (heightSpecMode == MeasureSpec.AT_MOST) { + setMeasuredDimension(widthSpecSize, (int) height); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + // 中心点 + centerPoint.set(getWidth() / 2, height / 2); + // 计算圆弧显示的范围,height * 2 是因为圆弧的高度是根据园来算的,所以双倍才是半个圆 + oval.set(getWidth() / 2f - radius, (float) roundWidth, getWidth() / 2f + radius, height * 2 - roundWidth*2); + } + + @Override + protected void onDraw(Canvas canvas) { + + // 最外层圆弧 + canvas.drawArc(oval, 180, 180, false, outPaint); //绘制外层圆弧 + + // 进度圆弧 + if (nowPro > 0) { + innerPaint.setColor(roundColor); + } else { + innerPaint.setColor(getContext().getColor(R.color.color_f6)); + } + canvas.drawArc(oval, 180, 180f * nowPro / max, false, innerPaint); //绘制圆弧 + + // 文字从底部从下往上绘制。 + + int valueY = height - smallMargin; + + // 值 + float valueTextWidth = mValueTextPaint.measureText(valueText); + float unitTextWidth = mUnitTextPaint.measureText(unitText); + canvas.drawText(valueText, centerPoint.x - (valueTextWidth + unitTextWidth) / 2f, valueY, mValueTextPaint); + // 单位 + canvas.drawText(unitText, centerPoint.x + valueTextWidth / 2f - unitTextWidth / 2f + smallMargin, valueY, mUnitTextPaint); + + // 测量值的高度 + mValueTextPaint.getTextBounds(text, 0, text.length(), textRect); + + // 提示文字("高血压") + float textWidth = mTextPaint.measureText(text); + // 文字的高度 = 值的高度起点 - 值的高度 - 间距 + float textY = valueY - textRect.height() - textMargin; + canvas.drawText(text, centerPoint.x - textWidth / 2f, textY, mTextPaint); + } + + /** + * dp 转 px + */ + private int dp2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * sp 转 px + */ + private int sp2px(Context context, float spValue) { + final float scale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * scale + 0.5f); + } +} diff --git a/mylibrary/src/main/res/values/colors.xml b/mylibrary/src/main/res/values/colors.xml index 073c2d5..2f3fa90 100644 --- a/mylibrary/src/main/res/values/colors.xml +++ b/mylibrary/src/main/res/values/colors.xml @@ -29,5 +29,10 @@ + #F6F6F6 + #F15F15 + #FF3FF3 + #f25f25 + diff --git a/mylibrary/src/main/res/values/styles.xml b/mylibrary/src/main/res/values/styles.xml index 6c47106..338ed7a 100644 --- a/mylibrary/src/main/res/values/styles.xml +++ b/mylibrary/src/main/res/values/styles.xml @@ -52,4 +52,28 @@ true @null + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file