车队管理完善

This commit is contained in:
lijia 2024-02-07 17:12:21 +08:00
parent 4c51daa245
commit 8dcf3b77c7
15 changed files with 1005 additions and 61 deletions

View File

@ -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<WayBillBean, QuickViewHolder>() {
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)
}
}

View File

@ -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<Fragment>) : FragmentStateAdapter(fragmentActivity) {
private var fragmentList : MutableList<Fragment> =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)
}
}

View File

@ -95,7 +95,7 @@ class MineFragment : BaseFragment<FragmentMineBinding>(), View.OnClickListener {
private fun goTools(pos: Int) {
when (pos) {
0 -> {
ActivityUtils.startActivity(mContext, RulesActivity::class.java)
ActivityUtils.startActivity(mContext, CarTeamActivity::class.java)
}
1 -> {

View File

@ -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<ActivityCarTeamBinding>() {
private val mFragmentContainerHelper = FragmentContainerHelper()
var mFragments = mutableListOf<Fragment>(
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()
// }
}

View File

@ -21,6 +21,8 @@ import com.dahe.mylibrary.utils.ConvertUtils
*/
class WalletActivity : BaseActivity<ActivityWalletBinding>() {
override fun initView(savedInstanceState: Bundle?) {
setStatusHeightParams(binding.rlTop)
setTitleBar("钱包",true,true)
}
override fun initDate() {

View File

@ -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<FragmentWaybillListBinding>() {
override fun onFragmentVisibleChange(isVisible: Boolean) {
}
override fun onFragmentFirstVisible() {
var datas = mutableListOf<WayBillBean>(
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)
}
}

View File

@ -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<FragmentWaybillListBinding>() {
override fun onFragmentVisibleChange(isVisible: Boolean) {
}
override fun onFragmentFirstVisible() {
var datas = mutableListOf<WayBillBean>(
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)
}
}

View File

@ -15,11 +15,27 @@
</RelativeLayout>
<LinearLayout
android:id="@+id/llTop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_100"
android:orientation="vertical">
<com.dahe.mylibrary.weight.CircleBarView
android:id="@+id/circleBarView"
android:layout_width="300dp"
android:layout_height="@dimen/dp_150"
app:progress_color1="@color/red"
/>
<com.dahe.mylibrary.weight.CircleBarView2
android:id="@+id/circleBarView2"
android:layout_width="300dp"
android:layout_height="@dimen/dp_150"
app:progress_color1="@color/red"
/>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="@dimen/dp_75"
@ -75,60 +91,31 @@
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_marginTop="@dimen/dp_10"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_50"
android:layout_height="@dimen/dp_54"
android:layout_marginLeft="@dimen/dp_15"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_15"
android:background="@color/white"
android:layout_marginBottom="@dimen/dp_14"
app:cardCornerRadius="@dimen/dp_8">
<LinearLayout
<net.lucode.hackware.magicindicator.MagicIndicator
android:id="@+id/magicIndicator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="@dimen/dp_12">
/>
<ImageView
android:layout_width="@dimen/dp_48"
android:layout_height="@dimen/dp_48"
android:background="@drawable/head_defaut" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:text="王师傅的车队"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_6"
android:background="@drawable/shape_orange_5"
android:paddingLeft="@dimen/dp_4"
android:paddingTop="@dimen/dp_2"
android:paddingRight="@dimen/dp_4"
android:paddingBottom="@dimen/dp_2"
android:text="未认证"
android:textColor="#FF4A02"
android:textSize="@dimen/sp_9" />
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/right_gray" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
<androidx.viewpager2.widget.ViewPager2
android:layout_below="@+id/llTop"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>

View File

@ -4,27 +4,13 @@
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rlTop"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_237"
android:background="@drawable/wallet_bg"
android:paddingTop="@dimen/dp_50">
android:background="@drawable/wallet_bg">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="钱包"
android:textColor="@color/white"
android:textSize="@dimen/sp_17" />
<include layout="@layout/common_toolbar"></include>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_4"
android:background="@drawable/left"
android:baselineAlignBottom="@+id/tvTitle" />
</RelativeLayout>
<RelativeLayout

View File

@ -5,7 +5,7 @@
android:orientation="vertical">
//搜索
<!-- //搜索-->
<RelativeLayout
android:layout_width="match_parent"

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_70"
android:background="@drawable/shape_bg8"
android:gravity="center_vertical">
<ImageView
android:id="@+id/ivHead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/head_defaut" />
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_12"
android:layout_toRightOf="@+id/ivHead"
android:text="王师傅"
android:textColor="@color/black"
android:textSize="@dimen/sp_16" />
<TextView
android:id="@+id/tvPhone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/ivHead"
android:layout_marginLeft="@dimen/dp_12"
android:layout_toRightOf="@+id/ivHead"
android:text="15835201103"
android:textColor="@color/color_9"
android:textSize="@dimen/sp_12" />
<View
android:layout_alignBottom="@+id/tvPhone"
android:layout_toRightOf="@+id/tvPhone"
android:layout_marginLeft="@dimen/dp_10"
android:layout_width="@dimen/dp_1"
android:layout_marginBottom="@dimen/dp_2"
android:layout_height="@dimen/dp_10"
android:background="@color/color_c"
/>
<TextView
android:id="@+id/tvDays"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/ivHead"
android:layout_marginLeft="@dimen/dp_22"
android:layout_toRightOf="@+id/tvPhone"
android:text="加入22天"
android:textColor="@color/color_9"
android:textSize="@dimen/sp_12" />
</RelativeLayout>

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -29,5 +29,10 @@
<color name="color_f6">#F6F6F6</color>
<color name="color_f15">#F15F15</color>
<color name="color_ff3">#FF3FF3</color>
<color name="color_f25">#f25f25</color>
</resources>

View File

@ -52,4 +52,28 @@
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<declare-styleable name="CircleBarView">
<attr name="progress_color1" format="reference|color"></attr>
<attr name="progress_color2" format="reference|color"></attr>
<attr name="progress_color3" format="reference|color"></attr>
<attr name="bg_color" format="color"></attr>
<attr name="bar_width" format="dimension"></attr>
<attr name="circle_width" format="dimension"></attr><!--背景圆弧宽度 -->
<attr name="circle_height" format="dimension"></attr><!--背景圆弧高度 -->
<attr name="anchor_radius" format="dimension"></attr>
<attr name="anchor_bg_radius" format="dimension"></attr>
<attr name="anchor_color" format="reference|color"></attr>
<attr name="anchor_bg_color" format="reference|color"></attr>
<attr name="progress_max" format="integer"></attr>
</declare-styleable>
<declare-styleable name="CircleTextView">
<attr name="paddingRing2Bg" format="dimension"></attr>
<attr name="ringStrokeWidth" format="dimension"></attr>
<attr name="ringColor1" format="reference|color"></attr>
<attr name="ringColor2" format="reference|color"></attr>
<attr name="bgColor1" format="reference|color"></attr>
<attr name="bgColor2" format="reference|color"></attr>
</declare-styleable>
</resources>