Android一个包含表格的图标库

之前有写过一个图表lib,但是开发的速度,大多很难跟上产品需求变化的脚步,所以修改了下原先的图表库,支持图表下面能整合table显示对应的类目,用曲线替换了折线,支持多曲线的显示,增加了显示的动画,,增加了一些可定制的属性,支持水平柱状图和叠加柱状图,以及多曲线图和饼状图的显示

1.效果图

image

2.各种图表的使用方式

1.饼状图 这个和原先的使用一样,只不过增加了一个动画,可以参看之前的文章,饼状图使用

2.水平多柱状图

2.1 xml布局

1 <wellijohn.org.varchart.hor_bar_with_line_chart.ChartLine 2 android:id="@+id/chartline" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:background="@color/white" 6 app:default_x_visible_num="4.2"//一个屏幕中显示多少列 7 app:y_interval="40dp"//Y轴的间距 8 app:y_num_text_max_width="56dp"//y轴左边的文字的宽度 /> 9还有y_visible_num:y轴需要显示几列

2.2 数据设置

1public class HorBarActivity extends AppCompatActivity { 2 3 4 //显示的坐标点 5 private ChartLine mChartline; 6 7 8 //多条折线的坐标点 9 private List<List<DotVo>> mMulListDisDots; 10 11 12 13 14 //x轴的点 15 private String[] mXdots = new String[]{"08/18" 16 , "08/19", 17 "08/20", "08/21", "08/22", "08/23", "08/24", 18 "08/25", "08/26", "08/27", "08/28", "08/29", "09/01", "09/02", "09/23", 19 }; 20 21 private double mMax = 44; 22 private Random rand = new Random(); 23 private List<CategoryVo> mCategoryList; 24 @Override 25 protected void onCreate(@Nullable Bundle savedInstanceState) { 26 super.onCreate(savedInstanceState); 27 setContentView(R.layout.activity_hor_bar); 28 29 30 initView(); 31 initMulTestData(); 32 initCategoryList(); 33 try { 34 mChartline.setYAxisMaxValue(mMax).setXdots(mXdots).setAnimationOpen(true).setListDisDots(mMulListDisDots). 35 setCategoryList(mCategoryList).reDraw(); 36 } catch (YCoordinateException e) { 37 Log.d("MainActivity", "onCreate: "); 38 e.printStackTrace(); 39 } 40 } 41 42 /** 43 * 柱状图的数据,是一个list,一个CategoryVo,就是一列中增加一个柱状 44 * CategoryVo:{ 45 * 卡券类目的名称 46 * private String categoryName; 47 * 每个卡券类目的值 48 * private List<String> categoryValueList; 49 * } 50 */ 51 private void initCategoryList() { 52 mCategoryList = new ArrayList<>(); 53 mCategoryList.add(new CategoryVo()); 54 mCategoryList.add(new CategoryVo()); 55 mCategoryList.add(new CategoryVo()); 56 } 57 58 /** 59 * 初始化曲线图,private List<List<DotVo>> mMulListDisDots; 60 * List<DotVo>>就是一条曲线图, 61 */ 62 private void initMulTestData() { 63 mMulListDisDots = new ArrayList<>(); 64 for (int i = 0; i < 3; i++) { 65 ArrayList<DotVo> temp = new ArrayList(); 66 DotVo tempDotVo = new DotVo("08/18", rand.nextInt((int) mMax)); 67 temp.add(tempDotVo); 68 DotVo tempDotVo1 = new DotVo("08/19", rand.nextInt((int) mMax)); 69 temp.add(tempDotVo1); 70 DotVo tempDotVo2 = new DotVo("08/20", rand.nextInt((int) mMax)); 71 temp.add(tempDotVo2); 72 DotVo tempDotVo3 = new DotVo("08/21", rand.nextInt((int) mMax)); 73 temp.add(tempDotVo3); 74 DotVo tempDotVo4 = new DotVo("08/22", rand.nextInt((int) mMax)); 75 temp.add(tempDotVo4); 76 DotVo tempDotVo5 = new DotVo("08/23", rand.nextInt((int) mMax)); 77 temp.add(tempDotVo5); 78 DotVo tempDotVo6 = new DotVo("09/02", rand.nextInt((int) mMax)); 79 temp.add(tempDotVo6); 80 81 82 mMulListDisDots.add(temp); 83 } 84 } 85 86 private void initView() { 87 mChartline = findViewById(R.id.chartline); 88 } 89} 90 91

3.叠加柱状图

3.1 xml布局

1<wellijohn.org.varchart.overlay_bar_with_line_chart.OverLayBarChartLine 2 android:id="@+id/overlay_chart_line" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:background="@color/white" 6 android:visibility="visible" 7 app:overlay_default_x_visible_num="4.2" 8 app:overlay_y_interval="40dp" 9 app:overlay_y_num_text_max_width="56dp" />

3.2 数据设置,如2.2一样

3.实现的几个关键点

3.1 宽度需要重写,onMeasure,因为的控件的宽度是大于屏幕的宽度的,宽度是根据显示的x轴的点和间距,以及y轴坐标的文字的所占的宽度的距离所组成。

1 int widthParentMeasureMode = MeasureSpec.getMode(widthMeasureSpec); 2 int widthParentMeasureSize = MeasureSpec.getSize(widthMeasureSpec); 3 int heightParentMeasureMode = MeasureSpec.getMode(heightMeasureSpec); 4 int heightParentMeasureSize = MeasureSpec.getSize(heightMeasureSpec); 5 int resultWidthSize = 0; 6 int resultHeightSize = 0; 7 int resultWidthMode = MeasureSpec.EXACTLY;//用来对childView进行计算的 8 int resultHeightMode = MeasureSpec.EXACTLY; 9 int paddingWidth = getPaddingLeft() + getPaddingRight(); 10 int paddingHeight = getPaddingTop() + getPaddingBottom(); 11 ViewGroup.LayoutParams thisLp = getLayoutParams(); 12 switch (widthParentMeasureMode) { 13 //父类不加限制给子类 14 case MeasureSpec.UNSPECIFIED: 15 //这个代表在布局写死了宽度 16 if (thisLp.width > 0) { 17 resultWidthSize = thisLp.width; 18 resultWidthMode = MeasureSpec.EXACTLY; 19 } else { 20 resultWidthSize = (int) (getYMaxTextWidth() + mXinterval * mXdots.length); 21 resultWidthMode = MeasureSpec.UNSPECIFIED; 22 } 23 break; 24 case MeasureSpec.AT_MOST: 25 //这个代表在布局写死了宽度 26 if (thisLp.width > 0) { 27 resultWidthSize = thisLp.width; 28 resultWidthMode = MeasureSpec.EXACTLY; 29 } else if (thisLp.width == ViewGroup.LayoutParams.MATCH_PARENT) { 30 resultWidthSize = Math.max(0, widthParentMeasureSize - paddingWidth); 31 resultWidthMode = MeasureSpec.AT_MOST; 32 } else if (thisLp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 33 resultWidthSize = (int) (getYMaxTextWidth() + mXinterval * mXdots.length); 34 resultWidthMode = MeasureSpec.AT_MOST; 35 } 36 break; 37 case MeasureSpec.EXACTLY: 38 //这个代表在布局写死了宽度 39 if (thisLp.width > 0) { 40 resultWidthSize = Math.min(widthParentMeasureSize, thisLp.width); 41 resultWidthMode = MeasureSpec.EXACTLY; 42 } else if (thisLp.width == ViewGroup.LayoutParams.MATCH_PARENT) { 43 resultWidthSize = widthParentMeasureSize; 44 resultWidthMode = MeasureSpec.EXACTLY; 45 } else if (thisLp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { 46 resultWidthSize = (int) (getYMaxTextWidth() + mXinterval * mXdots.length); 47 resultWidthMode = MeasureSpec.AT_MOST; 48 } 49 break; 50 } 51 52 53 54 55 setMeasuredDimension(MeasureSpec.makeMeasureSpec(resultWidthSize, resultWidthMode), 56 MeasureSpec.makeMeasureSpec(resultHeightSize, resultHeightMode));

3.2 规划固定的区域,在超出区域的部分不可见,这个在之前用的bitmap来实现,总感觉别扭,后面读官方的源码的时候,了解了canvas的clipRect方法,我们在绘制这块的时候,onDraw方法中调用

1 int clipRestoreCount = canvas.save(); 2 canvas.clipRect(mContentRect);//绘制之前调用 3 doDraw();//进行想要的绘制 4 canvas.restoreToCount(clipRestoreCount);//绘制完成调用restoreToCount恢复到绘制这块之前的状态

3.3 动画我们基本都可以用ValueAnimator来实现,比如说饼状图:他的一个绘制是0-360的角度的转变,我们就可以

1 private void startPathAnim(long duration) { 2 ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 360); 3 valueAnimator.setDuration(duration); 4 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 5 6 7 @Override 8 public void onAnimationUpdate(ValueAnimator animation) { 9 mDrawAngle = (float) animation.getAnimatedValue(); 10 ViewCompat.postInvalidateOnAnimation(CirclePercentChart.this); 11 } 12 }); 13 14 15 valueAnimator.start(); 16 17 18 }

然后通过mDrawAngle来控制每次绘制的角度,这样就可以有从0-360度绘制的感觉,那个柱状图的动画也是一样的,以不变应万变。

3.4 贝塞尔曲线绘制的算法

1 if (i == 0) {// 第一条为二阶贝塞尔 2 path.moveTo(mDots[0], mDots[1] + (mLastHorLineY - mDots[1]) * mPhaseY);// 起点 3 } else { 4 float cpx = preX + (mDots[0] - preX) / 2.0f; 5 path.cubicTo(cpx, preY + (mLastHorLineY - preY) * mPhaseY, 6 cpx, mDots[1] + (mLastHorLineY - mDots[1]) * mPhaseY, 7 mDots[0], mDots[1] + (mLastHorLineY - mDots[1]) * mPhaseY);}

在绘制贝塞尔曲线,我仔细去查过这些控制点的计算规则,有根据三点,来计算出两个控制点,但是这样绘制出来在三个点内部曲线是很平滑的,但是在接下来的第四个点的衔接的时候,感觉不是很好,所以我还是用了上面的计算方法来计算控制点,算法我贴出来,参数分别是1,2,3的x和y坐标和弯曲系数

1public static ControlPonits getControlPoints(double x0, double y0, double x1, double y1, double x2, double y2, double paramCoefficient) { 2 double d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)); 3 double d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); 4 double fa = paramCoefficient * d01 / (d01 + d12); // scaling factor for triangle Ta 5 double fb = paramCoefficient * d12 / (d01 + d12); // ditto for Tb, simplifies to fb=t-fa 6 double p1x = x1 - fa * (x2 - x0); // x2-x0 is the width of triangle T 7 double p1y = y1 - fa * (y2 - y0); // y2-y0 is the height of T 8 double p2x = x1 + fb * (x2 - x0); 9 double p2y = y1 + fb * (y2 - y0); 10 ControlPonits tempControlPoints = new ControlPonits(); 11 12 13 tempControlPoints.beforeControlPointX = (float) p1x; 14 tempControlPoints.beforeControlPointY = (float) p1y; 15 tempControlPoints.afterControlPointX = (float) p2x; 16 tempControlPoints.afterControlPointY = (float) p2y; 17 return tempControlPoints; 18 }

3.library引入方式

1step 1. Add it in your root build.gradle at the end of repositories: 2 3 4allprojects { 5repositories { 6... 7maven { url 'https://jitpack.io' } 8} 9} 10Step 2. Add the dependency 11 12 13dependencies { 14 compile 'com.github.WelliJohn:charts:1.0.0' 15}

github地址,您的点赞和star是我继续开源的最大动力。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

皕杰报表(关于日期时间时分秒显示不出来)

在使用皕杰报表设计器时,数据据里面是日期型,但当你web预览时候,发现有日期时间类型的数据时分秒显示不出来,只有年月日能显示出来,时分秒显示为0:00:00。1.可以使用tochar解决,数据集用selecttochar(flowdate,"yyyyMMddHH:mm:ss")fromtablename2.也可以把数据库日期类型date改成timestamp

皕杰报表之柱状图

1.当我们想设置柱状图时,可以在皕杰报表内,鼠标右键设置类型选择图表类型,鼠标双击图表,选择柱状图和图标模式普通柱状图。可以设置为水平方向。2.选择数据设定,在‘分类轴’和‘系列’中分别设定其值或者表达式。3.选择显示格式,一般图表包括图表区,标题与图例,X轴,Y轴和警戒线。图表颜色:设置图表数据区以外的背景色和字体颜色。数据区颜色:设置数据区内的背景颜色和

Android So动态加载 优雅实现与原理分析

背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我